我看到有人用 MD5 多次加密用户密码以提高安全性。我不确定这是否有效,但看起来不太好。那么,这有意义吗?
4 回答
让我们假设您使用的散列函数将是一个完美的单向函数。然后您可以像“随机预言机”一样查看它的输出,它的输出值在有限的值范围内(MD5 为 2^128)。
现在如果你多次应用哈希会发生什么?输出仍将保持在相同的范围内 (2^128)。就像你在说“猜猜我的随机数!” 二十次,每次都在想一个新数字——这并不会使猜测变得更难或更容易。没有比随机更“随机”的了。这不是一个完美的类比,但我认为它有助于说明问题。
考虑到暴力破解密码,您的方案根本不会增加任何安全性。更糟糕的是,您唯一可以“完成”的事情就是通过引入一些利用哈希函数重复应用的可能性来削弱安全性。这不太可能,但至少可以保证你肯定不会赢得任何东西。
那么,为什么这种方法仍然没有全部丢失呢?这是因为其他人提出的关于有数千次迭代而不是二十次迭代的概念。为什么这是一件好事,会减慢算法速度?这是因为大多数攻击者会尝试使用字典(或使用常用密码的彩虹表)来获取访问权限,希望您的一个用户疏忽大意以使用其中一个(我有罪,至少 Ubuntu 在安装时告诉我) . 但另一方面,要求您的用户记住 30 个随机字符是不人道的。
这就是为什么我们需要在易于记忆的密码之间进行某种形式的权衡,同时让攻击者尽可能难以猜测它们。有两种常见的做法,盐和通过应用某些函数的大量迭代而不是单个迭代来减慢过程。PKCS#5是一个很好的例子。
在您的情况下,应用 MD5 20000 而不是 20 次会显着降低攻击者使用字典的速度,因为他们的每个输入密码都必须经过 20000 次散列的普通过程才能仍然用作攻击。请注意,此过程不会影响如上所示的暴力破解。
但是为什么使用盐仍然更好呢?因为即使您应用哈希 20000 次,足智多谋的攻击者也可以预先计算一个大型密码数据库,对每个密码进行 20000 次哈希,从而有效地生成专门针对您的应用程序的自定义彩虹表。完成此操作后,他们可以很容易地攻击您的应用程序或使用您的方案的任何其他应用程序。这就是为什么您还需要为每个密码生成高成本,以使此类彩虹表无法使用。
如果您想真正安全,请使用 PKCS#5 中说明的 PBKDF2 之类的东西。
散列密码不是加密。这是一个单向过程。
查看security.stackexchange.com和密码相关问题。它们非常受欢迎,我们专门整理了这篇博客文章,以帮助个人找到有用的问题和答案。
这个问题专门讨论了连续 20 次使用 md5 - 查看 Thomas Pornin 的答案。他的回答要点:
- 20太低了,应该是20000以上——密码处理还是太快了
- 没有盐:攻击者可以以非常低的每个密码成本攻击密码,例如彩虹表 - 可以为任意数量的 md5 周期创建
- 由于没有确定的测试可以知道给定算法是否安全,因此发明自己的密码学通常会导致灾难。不要这样做
在 crypto.SE 上有这样一个问题,但现在不公开。Paŭlo Ebermann的回答 是:
对于密码散列,您不应使用普通的加密散列,而应使用专门用于保护密码的东西,例如 bcrypt。
有关详细信息,请参阅如何安全地存储密码。
重要的一点是密码破解者不必暴力破解哈希输出空间(SHA-1 为 2 160),而只需破解密码空间,该空间要小得多(取决于您的密码规则 - 通常字典会有所帮助)。因此,我们不想要一个快速的 散列函数,而是一个慢的散列函数。Bcrypt 和朋友就是为此而设计的。
类似的问题有以下答案: 问题是“防范密码分析突破:结合多个散列函数” Thomas Pornin的回答:
结合是SSL/TLS对 MD5 和 SHA-1 所做的,在其内部“PRF”(实际上是一个密钥派生函数)的定义中。对于给定的哈希函数,TLS 定义了一个依赖于 HMAC 的 KDF,而 HMAC 又依赖于哈希函数。然后 KDF 被调用两次,一次使用 MD5,一次使用 SHA-1,结果一起进行异或运算。这个想法是为了抵制 MD5 或 SHA-1 中的密码分析中断。请注意,对两个散列函数的输出进行异或运算依赖于微妙的假设。例如,如果我定义 SHB-256( m ) = SHA-256( m ) XOR C,对于固定常数C,那么 SHB-256 与 SHA-256 一样好;但两者的异或总是产生 C,这对于散列目的根本不好。因此,TLS 中的构造并没有真正得到科学权威的认可(只是碰巧没有被破坏)。TLS-1.2不再使用这种组合;它依赖于具有单个可配置散列函数的 KDF,通常是 SHA-256(这是 2011 年的明智选择)。
正如@PulpSpy 指出的那样,连接不是构建散列函数的通用方式。这由 Joux 在 2004 年发表,然后由Hoch 和 Shamir 在 2006 年推广,用于涉及迭代和连接的大型构造。但请注意小字:这并不是真正要解决哈希函数中的弱点,而是要让你的钱物有所值。也就是说,如果你取一个 128 位输出的哈希函数和另一个 160 位输出的哈希函数,并将结果连接起来,那么抗碰撞性不会比两者中最强的一个差;Joux 所表明的是,它也不会好很多。对于 128+160 = 288 位的输出,您可以瞄准 2 144阻力,但 Joux 的结果意味着您不会超过 2 87左右。
所以问题就变成了:如果可能的话,有没有一种有效的 方法来组合两个散列函数,使得结果与两者中最强的一样抗碰撞,但不会导致连接的输出扩大?2006 年,Boneh 和 Boyen发表了一个结果,简单地说答案是否定的,条件是每个哈希函数只评估一次。编辑: Pietrzak在 2007 年解除了后一种情况(即多次调用每个散列函数并没有帮助)。
通过PulpSpy:
我相信@Thomas 会给出一个彻底的答案。在此期间,我只想指出,您的第一个结构 H1(m)||H2(M) 的抗碰撞性并不比 H1(M) 好多少。见本文第 4 节:
http://web.cecs.pdx.edu/~teshrim/spring06/papers/general-attacks/multi-joux.pdf
不,这不是一个好习惯,您必须使用 $salt 进行加密,因为可以使用彩虹表破解密码