将用户密码的哈希值存储在数据库中是不安全的,因为人类密码容易受到字典攻击。每个人都建议通过使用盐来缓解这种情况,但盐被认为是不敏感的,不需要保护。
如果攻击者有盐,他的字典攻击如何变得比以前更困难?无法有效地获取盐是否会消除其有用性?
将用户密码的哈希值存储在数据库中是不安全的,因为人类密码容易受到字典攻击。每个人都建议通过使用盐来缓解这种情况,但盐被认为是不敏感的,不需要保护。
如果攻击者有盐,他的字典攻击如何变得比以前更困难?无法有效地获取盐是否会消除其有用性?
Salt 并不能保护您免受只使用一个密码的单独攻击者的攻击。只想破解一个密码的攻击者将计算hash(salt + guess)
而不是hash(guess)
(如果密码方案是hash(salt+password)
)。
如果攻击者想要破解许多密码,Salt 会有所帮助。通常是这种情况。有时,攻击者正在攻击一个站点并想要侵入该站点上的一个帐户,任何帐户。没有盐,攻击者的大部分工作都可以用于所有帐户,因此她可以一次针对所有帐户测试她的每次尝试。使用正确选择的盐(即如果没有两个帐户具有相同的盐),攻击者必须为每个散列密码重新开始。
此外,从某种意义上说,所有的密码破解尝试都是试图一次破解所有账户密码。那是因为可以预先计算哈希值。只需要某人生成一个哈希表——或者更有效地,一个彩虹表——并且初始工作可以分配给多个攻击者,这些攻击者可以在使用相同密码哈希算法的任何帐户数据库上使用它。同样,盐使这些预计算变得无用。
暴力密码攻击可以总结如下:
hash(guess[i]) = hashed_password[j]
.在一个简单的方法中,第二步需要n × p哈希计算来尝试对所有帐户的所有猜测。但是,如果第一步已经计算了所有可能的哈希,那么第二步根本不需要哈希计算,只是测试每个hashed_password
是否在预先计算的数据库中,所以攻击只需要n次表查找(这甚至可以加快,但是我们已经从n x p慢速计算¹下降到n表查找)。
如果每个密码都有不同的盐值,那么为了有用,预计算必须包含每个可能的盐值的条目。如果盐足够大,则预计算是不可行的。如果预计算不考虑盐,那么加快第二步的速度就没有用处,因为任何加密散列函数都会“混合”其输入:知道 的散列UIOQWHHXpassword
并不能帮助计算 的散列NUIASZNApassword
。即使要攻击单个帐户,攻击者也需要执行p哈希计算来尝试所有猜测,这已经是对单个表查找的改进,如果攻击者有一个预先计算的字典就足够了。
¹密码不应存储为 SHA-1 等散列,而应使用bcrypt 或 scrypt 或 PBKDF2等较慢的散列函数。
我将解释数据库存储密码的每个安全级别,也许这将有助于阐明盐的重要性。
级别 1:密码以明文形式存储在数据库中。
这只是纯粹的愚蠢。但有时,大公司的数据库遭到入侵,而且,令人惊讶的是,所有密码都以明文形式存储。真可惜!
级别 2:使用散列算法存储的密码。
这是迈向更安全的一步。如果攻击者获得散列密码,他仍然无法使用此凭据登录服务。他首先必须使用Rainbow Table或通过暴力破解来“解散”密码。这意味着攻击者需要做更多的工作,但仍然可以检索原始密码。
第 3 级:使用带有盐的散列算法存储的密码。
这开始很有趣。正如我们在Level 2中看到的那样,有权访问散列密码的攻击者可以暴力破解它或使用彩虹表。在原始密码中添加盐会使彩虹表完全无用,因为它们没有考虑盐。仍然可以使用彩虹表获取原始字符串,但这意味着彩虹表中存在密码+盐。由于盐通常很长,因此具有字符串哈希值(40+)的奇数几乎是不可能的。剩下的唯一解决方案是蛮力。
第 4 级:使用带有 salt 和 peper 的散列算法存储的密码。
这很有趣(这就是我发布答案的原因,因为实际答案已经很有趣了)。
我建议您使用像 BCrypt、SCrypt 或 PBKDF2 这样的散列算法,因为它们到目前为止还没有被破解,而且破解速度非常慢,增加破解时间,然后是完整的密码数据库。
盐和胡椒的区别在于它们的位置。盐通常存储在数据库中,但辣椒位于代码中。这看起来很奇怪,但最初的想法是数据库可以被破坏,但代码不会被破坏,给攻击者留下一个盐和一个无用的哈希密码列表。此外,它为散列密码增加了更多的复杂性,使彩虹表完全无用(如果我们认为它们仍然有点用盐的话!)。
在只有数据库被破坏的情况下,即使是暴力破解也是无用的,因为攻击者不是在寻找一个值(原始密码),而是寻找两个值(原始密码和胡椒)。
如果你的散列是未加盐的,我可以生成一个完整的散列字典并将它们存储在数据库中(称为彩虹表的特殊类型,它对大量散列更有效),那么我需要做的就是查找它们。基本上是一个巨大的内存与 CPU 时间优化。此外,如果我看到两个用户具有相同的哈希值,我知道他们使用的是相同的密码。
盐使每个用户的密码散列都是唯一的,如果你做得对,即使他们在其他网站上使用相同的密码(并不罕见),它也可能是唯一的,所以我实际上不得不接受,应用盐和散列它,重复字典中的下一个条目。
未加盐的哈希很容易受到查找攻击。有免费可用的数据库包含数百万个密码哈希(主要是 MD5 和 SHA1),可用于查找哈希的明文。这些可能基于标准的关系数据库,或者基于专门的数据库格式,如彩虹表。
所以,这里有一个例子:(未加盐的
7c6a61c68ef8b9b6b061b28c348bc1ed7921cb53
)
2d67062d67b4d0eaca31a768e901d04982de7352
(用“RxB6aE”前缀加盐)
快速查找第一个哈希将显示明文为“passw0rd”。但是,后者不太可能被发现。在攻击者不知道盐的情况下,它会使字典和蛮力攻击变得困难。
如果你想保护数据库中的密码,你应该使用 bcrypt 之类的东西。它使用哈希算法的大量迭代来使每次计算变慢。因此,蛮力攻击、字典攻击和彩虹表的构建是非常不可行的。