由于引入了Rainbow 表,并且仅使用散列密码(例如:MD5)将密码存储在数据库中,这并不是最好的安全方式。
当人们谈论加盐哈希时,总是以这种方式hash(password . salt)
甚至hash(hash(password) . salt)
.
我不知道为什么要使用盐,并为每个密码添加额外的条目来存储盐?为什么我们不直接使用hash(hash(password))
, 甚至hash(hash(hash(password)))
?
放盐更安全吗?还是只是更复杂的感觉?
由于引入了Rainbow 表,并且仅使用散列密码(例如:MD5)将密码存储在数据库中,这并不是最好的安全方式。
当人们谈论加盐哈希时,总是以这种方式hash(password . salt)
甚至hash(hash(password) . salt)
.
我不知道为什么要使用盐,并为每个密码添加额外的条目来存储盐?为什么我们不直接使用hash(hash(password))
, 甚至hash(hash(hash(password)))
?
放盐更安全吗?还是只是更复杂的感觉?
您可以基于 hash(hash(pwd)) 的字典构建彩虹表,只需两倍于 hash(pwd) 的时间(甚至更少,因为性能主要与磁盘写入有关)并且它甚至不会更大。使用 salt 极大地扩展了 table 所需的大小,直到它变得不切实际。
此外(更重要的是),用户通常拥有相同的密码。如果每个用户没有单独的盐,如果您破坏了一个用户的密码,那么您就破坏了具有相同密码的所有其他用户。
为简单起见,让我们假设每个人都使用数字作为密码。
如果每个人都使用 8 位数字作为密码,那就有 100,000,000 种可能性。如果您试图破坏系统,则需要对所有这些可能性进行散列。如果你有一个“hash of hash of hash”,你仍然只需要对这 100,000,000 种可能性进行散列 - 只是以稍微复杂的方式。
现在让我们假设我们也有一个 4 位数的盐。现在,不是 100,000,000 种可能性,而是 1,000,000,000,000 种……我们给潜在攻击者 10,000 倍的工作量,而不是 3 倍的工作量。
基本上,将盐视为一种人为地使每个人的密码变长的方法,从而扩展了字典攻击必须处理的空间。
编辑:为了清楚起见,鉴于盐也是以纯文本形式提供的,您仍然只有 100,000,000 种可能性来尝试攻击任何一个 hash。然而,这意味着在尝试了一个密码的这些可能性之后,攻击者将没有任何有用的信息来攻击另一个密码。如果没有盐,攻击者可以创建一个包含 100,000,000 种可能性的字典,然后知道数据库中的所有密码,只需要它们的哈希值。换句话说,盐有助于防止散装攻击。它们还意味着您不能预先生成字典:为了有效地攻击单个密码,您必须事先知道盐。如果没有盐,您可以在访问散列本身之前计算每个可能密码的散列。
如果你不使用盐,那么攻击者可以构建一个彩虹表来攻击你数据库中的每个密码。多次散列并不能在没有盐的情况下保护您,因为彩虹表通过以您描述的方式将散列链接在一起来工作: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 次迭代循环可以将一种可行的攻击转变为需要 100 年或更长时间的攻击。当计算机在 18 个月内加速时,只需将迭代次数更改为 2000 次。
salt、散列算法和迭代计数不需要保密,可以与计算的散列一起存储在您的数据库中。您可以选择固定的迭代次数和哈希算法,但必须为每个用户随机生成盐。
迭代哈希和使用盐都增加了密码哈希的安全性。但是它们可以防止完全不同的攻击。
迭代哈希会增加暴力攻击所需的工作量。但是你不应该像你建议的那样使用幼稚的迭代,而是为它设计的算法,比如PBKDF2
盐可以防止预先计算的表格,因此对于每个网站和用户来说它应该是不同的。
盐的目的是使字典攻击没有实际意义。现在,无论您对哈希进行多少重新哈希,相同的输入总是会产生相同的输出哈希,因此可以为此构建一个字典。因此,虽然多重哈希可能会使蛮力攻击变得更加困难,但它对字典攻击没有任何作用。
没有什么能阻止任何人为双重哈希密码构建 Rainbow 表。
我使用一种类似的方法来为登录的用户散列密码。在会话中生成一个盐(随机值)并发送给客户端。用户输入他们的密码,然后用盐进行哈希处理并发回。这确保了每次从服务器发送的值都是不同的,使得使用中间人攻击更难闯入。
salt 是特定于站点或用户的值。这意味着为了检索密码,攻击者必须既可以访问数据库又知道盐值。
此外,攻击者还可以另外生成一个表,然后将其用于多个站点。但是,使用盐,攻击者必须为每个站点生成一个表,甚至每个用户生成一次(使攻击速度变慢)。
特定于站点的盐对网站的安全性几乎没有增加。正如评论中所说,结合使用特定于站点的盐和特定于用户的盐可以显着提高安全性,而不是仅使用特定于站点的盐。
几年前,我在 stackoverflow 上问了一个关于密码存储的问题,这可能对您有所帮助。请参阅PHP 密码的安全哈希和盐。