翻译 | 哈希,生日和密码

2019-11-241915

原文自博客发布平台medium,作者为 Stefano Troìa,传送门

什么是哈希函数?

它是一种能够将任意长度的输入信息映射成唯一的固定长度的输出信息的一种算法,这样的算法也被称为 HASH、FINGERPRINT 或者 DIGEST。

它通常是被用于验证数据完整性的。事实上,数字签名算法是被应用于摘要(DIGEST)当中,而非整个文件内容。

什么是哈希碰撞?

哈希函数的每一个输入都会被映射为不同的摘要输出当中,但这结论并非百分比正确,因是存在产生同一个结果的可能性。在这种情况下,我们发现其中产生了冲突,而跟进一步来说,每个输出都有可能存在无限的冲突。

所以这代表什么?

哈希函数的安全是基于这么一个事实:即使知道具体的哈希值,也很难去找到当中的冲突。这是实现的基础,假设我们已经对文档进行了签名处理,某些非法分子知道如何通过计算来攻击我们,那么这类的碰撞就是指他们产生了跟我们相同的摘要签名。

所以,在使用哈希函数的时候,我们必须确保在计算上不允许产生碰撞,这种安全性做法是基于生日悖论来尝产生的。

什么是生日悖论(Birthday paradox)?

这基于一个问题:我要考虑同一天至少有2个人出生的概率大于50%。

所以我们要思考,在一群人当中,给定当中的 n 人,我们可以通过一个简单的组合公式来计算出总可能性:

在这当中,n 表示在总共 k 个人中给定的同个组的人的数量。在我们的例子中是2。

当有57个人时,有两个人出生于同一天的概率达到了99%,考虑到我们这里有1596个组合并且一年有365天,所以忽略计算的话,答案是23(253对)。

哈希函数中的生日悖论

同样的想法也能应用于哈希函数当中,并且总所周知的是,对于 2^n/2 种可能的输入当中,发生碰撞的概率大于50%,其中 n 表示组成摘要的位数。

下面的表格展示位数和值的数量的关系。

生日攻击

生日攻击是由计算原始文档中的 n/2 变体来查找冲突。这说用使用至少256位作为摘要是多么重要。

##验证和哈希

哈希是用于存储密码的一个好方法,因为它在转换中不可逆而且是确定性的deterministic)。

一个确定性的函数是指给定相同的输入值,就会产生相同的输出值。显然这是验证中必须做到的,因为如果使用同一个密码可以登录到不同的账号,这会导致非常多的问题。

因此,在保存用户凭证的时候,我们通常将账号和哈希密码保存到数据库当中。当用户登录的时候,我们将密码进行哈希处理并连同账号跟存储值进行比较。如果两个值相等,则登录有效。

我们应该使用哈希来存储密码吗?

简单来说,是的。但是...

近年来,人们常说避免使用哈希来存储密码因为它是一个快捷的操作。但这不是意味着计算速度快会减低密码的安全性。例如,现代硬件每秒可以计算数十亿次 SHA-256 加密操作。除了快函数外,我们也需要在哈希加密中添加慢函数,这样就可以降低攻击者攻击的速度了。

通常我们使用 bcrypt(Blowfish-crypt)之类的自适应性哈希函数,它可以增加计算的迭代回合次数来使过程变得缓慢,因此在高计算能力的攻击下,它也可以抵抗一定的攻击。

结论

让我们回顾下这篇文章的知识点:

  • 哈希的核心目的是创建数据指纹来评估数据的完整性
  • 哈希函数接收任意输入,并将它们转换为固定长度的输出信息
  • 哈希不足以在大规模攻击中保护密码安全,使用加盐处理更能提高安全性
  • 据报道,MD5 和 SHA-1 由于碰撞问题更容易被攻击。SHA-2 系列是更好的选择
  • SHA 族谱不是理想的存储密码的算法,因为它非常快,容易受到暴力攻击,因此最好使用 bcrypt 来进行进一步处理
分享
点赞0
打赏
上一篇:Docker常用命令笔记(一)
下一篇:聊聊jsr-303接口参数校验