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

我说的是这样做:

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

而不是这样:

$hashed_password = hash($plaintext_password);

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

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

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

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


当前回答

让我们假设您使用哈希算法:计算rot13,取前10个字符。如果你这样做两次(甚至2000次),就有可能得到一个更快的函数,但结果是相同的(即只取前10个字符)。

同样,也可以创建一个速度更快的函数,其输出与重复哈希函数相同。因此,您对哈希函数的选择非常重要:与rot13示例一样,并没有给出重复哈希将提高安全性。如果没有研究表明该算法是为递归使用而设计的,那么假设它不会为您提供额外的保护是更安全的。

也就是说:对于除了最简单的哈希函数之外的所有函数,很可能需要密码学专家来计算更快的函数,所以如果你正在防范无法访问密码学专家的攻击者,在实践中使用重复哈希函数可能更安全。

其他回答

Yes.

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

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

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

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

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

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

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

我要大胆地说,在某些情况下,它更安全……不过先别给我投反对票!

从数学/密码学的角度来看,它不太安全,我相信其他人会给你一个比我更清楚的解释。

然而,存在大量的MD5哈希数据库,其中更可能包含“密码”文本而不是它的MD5。所以通过双重哈希,你会降低这些数据库的有效性。

当然,如果你使用盐,那么这个优点(缺点?)就消失了。

减少搜索空间的担忧在数学上是正确的,尽管搜索空间仍然足够大,对于所有实际目的(假设您使用盐),在2^128。然而,由于我们谈论的是密码,根据我的粗略计算,可能的16个字符的字符串(字母数字,大写,一些符号)的数量大约是2^98。所以搜索空间减少的感觉并不是真的相关。

除此之外,从密码学的角度来说,实际上没有什么不同。

Although there is a crypto primitive called a "hash chain" -- a technique that allows you to do some cool tricks, like disclosing a signature key after it's been used, without sacrificing the integrity of the system -- given minimal time synchronization, this allows you to cleanly sidestep the problem of initial key distribution. Basically, you precompute a large set of hashes of hashes - h(h(h(h....(h(k))...))) , use the nth value to sign, after a set interval, you send out the key, and sign it using key (n-1). The recepients can now verify that you sent all the previous messages, and no one can fake your signature since the time period for which it is valid has passed.

像Bill建议的那样重新哈希几十万次只是浪费你的cpu。如果你担心别人会破坏128位,可以使用更长的密钥。