在存储密码之前对密码进行两次哈希比只进行一次哈希更安全还是更不安全?

我说的是这样做:

$hashed_password = hash(hash($plaintext_password));

而不是这样:

$hashed_password = hash($plaintext_password);

如果它不太安全,你能提供一个好的解释(或一个链接)吗?

另外,使用哈希函数有区别吗?如果混合使用md5和sha1(例如),而不是重复相同的哈希函数,会有任何区别吗?

注1:当我说“双重哈希”时,我指的是对密码进行两次哈希,以使其更加模糊。我说的不是解决碰撞的技术。

注2:我知道我需要添加一个随机的盐,以真正使它安全。问题是用同一个算法进行两次哈希运算对哈希是有利还是有害。


当前回答

正如本文中的一些回应所建议的,在某些情况下,它可能会提高安全性,而在其他情况下,它肯定会损害安全性。有一种更好的解决方案肯定会提高安全性。不是将计算哈希的次数翻倍,而是将盐的大小翻倍,或者将哈希中使用的比特数翻倍,或者两者都做!从SHA-245跳到SHA-512。

其他回答

一般来说,它不会为双重哈希或双重加密提供额外的安全性。如果你能分解一次散列,你就能再分解一次。不过,这样做通常不会损害安全性。

在使用MD5的例子中,您可能知道有一些碰撞问题。“双重哈希”并不能真正帮助防止这种情况,因为相同的碰撞仍然会导致相同的第一个哈希,然后您可以再次MD5以获得第二个哈希。

这确实可以防止字典攻击,比如那些“反向md5数据库”,但盐也是如此。

在切线上,双重加密某些东西并不能提供任何额外的安全性,因为它所做的只是导致一个不同的密钥,这是实际使用的两个密钥的组合。因此寻找“钥匙”的工作不会加倍,因为实际上不需要找到两把钥匙。这对于哈希并不适用,因为哈希的结果通常与原始输入的长度不同。

一次哈希密码是不安全的

不,多重哈希并不是更不安全;它们是安全使用密码的重要组成部分。

迭代散列会增加攻击者尝试候选密码列表中的每个密码所需的时间。您可以轻松地将攻击密码所需的时间从数小时增加到数年。

简单的迭代是不够的

仅仅将哈希输出链接到输入不足以保证安全性。迭代应该在保留密码熵的算法上下文中进行。幸运的是,有几个已经发表的算法已经经过了足够的审查,使他们对自己的设计充满信心。

像PBKDF2这样的良好的密钥派生算法将密码注入到每一轮哈希中,从而减轻了对哈希输出中冲突的担忧。PBKDF2可以按原样用于密码身份验证。Bcrypt使用加密步骤进行密钥推导;这样,如果发现了反向密钥推导的快速方法,攻击者仍然必须完成已知的明文攻击。

如何破解密码

存储的密码需要防止离线攻击。如果密码没有加盐,它们可以被预先计算的字典攻击破坏(例如,使用彩虹表)。否则,攻击者必须花时间为每个密码计算哈希,并查看它是否与存储的哈希匹配。

并非所有密码的可能性都是一样的。攻击者可能会穷尽搜索所有短密码,但他们知道,每增加一个字符,暴力破解成功的几率就会急剧下降。相反,他们使用最可能的密码的有序列表。他们从“password123”开始,逐步使用不太常用的密码。

假设攻击者名单很长,有100亿候选人;再假设一个桌面系统每秒可以计算100万次哈希。如果只使用一次迭代,攻击者可以在不到3小时的时间内测试她的整个列表。但如果只使用2000次迭代,时间就会延长到近8个月。要打败一个更复杂的攻击者——例如,能够下载一个可以利用他们GPU能力的程序的攻击者——你需要更多的迭代。

多少才够?

使用的迭代次数是安全性和用户体验之间的权衡。攻击者可以使用的专用硬件很便宜,但它仍然可以每秒执行数亿次迭代。攻击者系统的性能决定了在给定的迭代次数下需要多长时间才能破解密码。但是您的应用程序不太可能使用这种专用硬件。在不惹恼用户的情况下,您可以执行多少迭代取决于您的系统。

您可能可以在身份验证期间让用户多等待3 / 4秒左右。分析您的目标平台,并使用尽可能多的迭代。我测试过的平台(移动设备上的一个用户,或者服务器平台上的许多用户)可以轻松地支持6万到12万次迭代的PBKDF2,或者成本因子为12或13的bcrypt。

更多的背景

Read PKCS #5 for authoritative information on the role of salt and iterations in hashing. Even though PBKDF2 was meant for generating encryption keys from passwords, it works well as a one-way-hash for password authentication. Each iteration of bcrypt is more expensive than a SHA-2 hash, so you can use fewer iterations, but the idea is the same. Bcrypt also goes a step beyond most PBKDF2-based solutions by using the derived key to encrypt a well-known plain text. The resulting cipher text is stored as the "hash," along with some meta-data. However, nothing stops you from doing the same thing with PBKDF2.

以下是我写的关于这个话题的其他答案:

哈希密码 哈希密码 盐 隐藏的盐 PBKDF2和bcrypt Bcrypt

Yes.

绝对不要使用传统哈希函数的多次迭代,比如md5(md5(md5(password)))。在最好的情况下,您将获得安全方面的边际增加(这样的方案几乎不能对GPU攻击提供任何保护;直接把它输送出来。)在最坏的情况下,每次添加迭代都会减少哈希空间(从而减少安全性)。在安全性方面,明智的做法是做最坏的打算。

请使用由合格的密码学家设计的密码,该密码是有效的密码哈希,并能抵抗暴力破解和时空攻击。其中包括bcrypt、scrypt,在某些情况下还包括PBKDF2。基于glibc sha -256的散列也是可以接受的。

双重哈希是丑陋的,因为攻击者很可能已经构建了一个表来提出大多数哈希。更好的方法是在哈希中加入盐,然后混合在一起。还有新的模式来“签署”散列(基本上是腌制),但以一种更安全的方式。

是的——它减少了可能匹配字符串的数量。

正如你已经提到的,咸散列更好。

这里有一篇文章:http://websecurity.ro/blog/2007/11/02/md5md5-vs-md5/,试图证明为什么它是等价的,但我不确定逻辑。一方面,他们假设没有软件可以分析md5(md5(文本)),但很明显,生成彩虹表是相当简单的。

我仍然坚持我的答案,md5(md5(文本))类型哈希的数量比md5(文本)哈希的数量少,增加了碰撞的机会(即使仍然是一个不太可能的概率),并减少了搜索空间。