hash(hash()) vs salted hash

3
自从引入了彩虹表,仅使用哈希密码(例如:MD5)来存储数据库中的密码不是最安全的方式。 当人们谈论盐哈希时,总是以这种方式使用hash(password . salt)或甚至hash(hash(password) . salt)。 我不知道为什么要使用盐,并为每个密码添加额外的条目以存储盐? 为什么不只使用hash(hash(password)),甚至hash(hash(hash(password)))? 添加盐更安全吗?还是只是感觉更复杂?

1
可能是哈希时“盐”的目的是什么?的重复问题。 - Lucero
9
为什么您认为在不加盐的情况下对哈希进行哈希处理会增加密码的安全性?这就像在没有从秘密食谱中添加任何额外调味品的情况下再搅拌面糊10分钟一样。 - BoltClock
8个回答

23
您可以基于字典构建一个 rainbow table 用于 hash(hash(pwd)),所需时间仅为 hash(pwd) 的两倍(实际上更短,因为性能主要取决于磁盘写入),而且它甚至不会更大。使用 salt 大大扩展了所需表格的大小,直到它变得不可行。

此外(更重要的是),用户经常使用相同的密码。如果没有为每个用户分配单独的 salt,则一旦破解了一个用户的密码,您就已经破解了所有其他使用相同密码的用户的密码。


但是你怎么知道哈希的确切迭代次数呢?这也算作加盐吗?关于你的第二段,只有在使用随机数而不是静态盐时才是一个解决方案。 - Alix Axel
2
嗯...第二段从未想过。这是使用每个用户盐的一个好论据。 - mpen
@Alix Axel:当然是这样的。我只是暗示了每个用户的盐值,由于这个问题和答案似乎很受欢迎,我会相应地修改答案。 - TToni

12
为了简单起见,让我们假设每个人都使用数字作为密码。
如果每个人都使用8位数字作为密码,那就有1亿种可能性。如果你试图破解系统,你需要对所有这些可能性进行哈希计算。如果你有一个“哈希的哈希的哈希”,你仍然只需要以稍微复杂的方式对这1亿个可能性进行哈希计算。
现在让我们假装我们还有一个4位数字的"盐"。现在,不是1亿种可能性,而是1,000,000,000,000 种可能性... 我们为潜在攻击者提供了10,000倍的工作量,而不仅仅是增加了3倍的工作量。
基本上,把盐看作一种人为地使每个人的密码变长的方法,从而扩大词典攻击可以处理的空间。
编辑:为了明确,鉴于盐也是以明文形式提供的,你仍然只有1亿种可能性来尝试攻击任何一个哈希值。然而,这意味着在尝试这些可能性之后,攻击者将没有任何有用的信息来攻击另一个密码。没有盐,攻击者可以创建一个包含1亿个可能性的字典,然后仅凭哈希值就知道数据库中的所有密码。换句话说,盐有助于防止批量攻击。它们还意味着你不能预先生成字典:为了有效地攻击单个密码,你必须事先知道盐。没有盐,你可以在访问哈希值之前计算出每个可能的密码的哈希值。

2
我没有点踩,但我认为你的解释有些误导。因为盐是已知的,所以猜测单个密码并不更难。它只是使得构建攻击多个密码的表更加困难,而且只有每个用户都有一个不可预测的盐才行。 - President James K. Polk

7
如果您不使用盐,则攻击者可以构建一个单一的彩虹表,用于攻击您数据库中的每个密码。即使多次哈希也不能在没有盐的情况下保护您,因为彩虹表通过以恰好您描述的方式链接哈希来工作:hash(hash(password))
如果为每个用户添加一个随机盐,则攻击者无法重复使用同一张表破解两个密码,因此他们的工作变得更加困难。另外的好处是,如果使用盐,则相同密码的两个用户将哈希为不同的值。
您迭代哈希的想法仍然很好,但您还需要盐。如果您这样做:
function hashPassword(password, salt) {
    result = hash(salt . password)
    for (i = 0; i < 1000; i++) {
        result = hash(salt . result)
    }
    return result
}

然后,您可以通过进行1000次迭代来使攻击者的工作增加1000倍,对正常用户的影响微乎其微。请注意,攻击者可以在单个低端计算机上每秒测试数百万个候选密码 - 哈希函数被设计为快速运行。这1000次迭代循环可以将可行的攻击变成需要100年甚至更长时间才能完成的攻击。当计算机在18个月后加速时,只需更改迭代次数为2000即可。
盐值、哈希算法和迭代次数不需要保密,并且可以与计算出的哈希值一起存储在数据库中。您可以选择一个固定的迭代次数和哈希算法,但是盐值必须为每个用户随机生成。

下投票者是否愿意发表评论?您有什么不同意的地方吗? - Cameron Skinner

4

迭代哈希和使用盐都可以提高密码哈希的安全性。但它们保护不同类型的攻击。

迭代哈希可以增加暴力破解所需的工作量。但你不应该像你建议的那样使用天真的迭代,而是使用专为此设计的算法,例如PBKDF2

盐可以防止预先计算的表格攻击,因此每个网站和用户都应该使用不同的盐。


0
盐的作用是使字典攻击无效。现在,无论你如何重新计算哈希值,相同的输入始终会产生相同的输出哈希值,因此可以为此构建一个字典。因此,虽然多次哈希可能会使暴力攻击更加困难,但对于字典攻击却没有任何作用。

@Jacco: “哈希”的作用是防止预计算攻击 - 请再说一遍? - Lucero
嗯,我没有重新阅读我的评论。加盐哈希的目的是为了防止预计算攻击。 - Jacco
@Jacco,我同意这一点。但这意味着它有助于抵御基于字典的攻击,假设字典是指一组预先计算好的值(也许我的字典定义是错误的)。 - Lucero
1
字典攻击利用许多密码基于实际单词(如收录在字典中)的事实。从字典中找到字符序列创建的8位字符串的熵比从随机字符串创建的熵要低得多。盐,根据定义而言非保密,不会改变散列字符串的熵。但是它确实(试图)确保每个散列都是不同的。因此,尝试字典攻击的攻击者需要分别攻击每个散列值。换句话说,攻击的计算结果无法被重复使用。 - Jacco
从上下文中我推断Lucero指的是一个预计算字典->哈希表,即一个预计算攻击。 - President James K. Polk
显示剩余2条评论

0

任何人都可以为双重哈希密码构建彩虹表,没有任何障碍。


0

我使用了一种可比较的方法对登录用户的密码进行哈希。在会话中生成一个盐(随机值)并发送给客户端。用户输入他们的密码,密码再与盐一起进行哈希,并将结果返回。这样确保从服务器发送的值每次都不同,使得利用中间人攻击更加困难。


-1

盐是一个站点或用户特定的值。 这意味着为了检索密码,攻击者必须同时访问数据库并知道盐。

此外,攻击者可以额外生成一张表,然后对多个站点使用它。但是,使用盐,攻击者必须为每个站点甚至每个用户生成一张表(使攻击变慢)。

站点特定的盐对网站的安全几乎没有什么帮助。正如评论中所说,使用站点特定和用户特定的盐的组合可以显著提高安全性,而不仅仅是站点特定的盐。

几年前,我在stackoverflow上问了一个有关密码存储的问题,这可能对您有所帮助。请参见PHP密码的安全哈希和盐


5
通常情况下,盐值通常保存在数据库中。毕竟,您希望每个用户都有不同的盐值-否则,具有相同密码的两个用户将具有相同的哈希值,这会造成安全漏洞。拥有一个单独的站点特定密钥意味着如果该密钥被破坏,则所有您的用户都会受到单个字典重新计算的影响而变得容易受攻击。 - Jon Skeet
2
@Jon是正确的:盐不是“站点特定”的。它应该为每个用户随机生成。请注意,盐不需要保密,也不应被视为保密。 - Cameron Skinner
1
当然,您可以使用多个盐值,例如一个用于网站 每个用户一个... - Lucero
1
@Jon Skeet - 为什么不两者兼备呢?部分是站点特定的,不在数据库中,另一部分是用户特定的,并且在数据库中?编辑:@Lucero Ops。没看到你的评论... - luiscubal
1
@Lucero:没有必要。每个用户只需要一个随机盐值即可,这样可以减少代码量和(可能)减少漏洞。不要声称使用更多的盐值会使攻击者更难攻击:事实并非如此。这是通过混淆来实现安全性,我们都知道这根本不是安全。 - Cameron Skinner
显示剩余7条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接