为什么散列密码的盐需要全局唯一,而不仅仅是系统/站点唯一?

信息安全 密码 哈希 密码破解 密码策略
2021-08-26 20:24:52

我正在阅读 Terry Chia 对另一个关于盐要求的问题的回答,他/她(以及其他人)在其中指定盐需要是全球唯一的,但没有详细说明原因。这被定义为“不仅在您的数据库上下文中是唯一的,而且在每个单个数据库的上下文中都是唯一的”。例如,我一直在使用电子邮件地址作为我的实验沙箱网站/数据库的盐。这些当然可以在其他网站上用作盐。

这对我来说没有意义,因为据我了解,salt 的目的是确保“一起破解多个受损密码哈希应该不会比单独破解它们更容易”(Ilmari Karonen,进一步向下同一篇文章)。除非我弄错了,只要我的盐在我的数据库中是唯一的,这个约束就可以满足。

我更加困惑,因为生成全球独特的盐听起来我无法控制。我应该如何保证我的盐从未在其他人的网站上使用过,那里有数百万个网站?公平地说,我还没有研究如何生成随机盐。也许这个想法是它们是从一个足够大的池中创建的,即使考虑到那里的站点数量,为单独的数据库生成重复盐的可能性也很小?

我绝对倾向于使用电子邮件地址作为我的盐,因为这是工作的一小步,但考虑到似乎不同意这种方法的人的数量,我认识到我可能错了。此外,我想更多地了解我为什么错了,因为它还没有意义。

3个回答

加盐的目标是抵抗预计算

虽然您不能保证盐是全球唯一的,但您可以(正如您所说)生成足够大小的盐,以使其无法提前生成彩虹表(使它们“足够独特”)。

更一般地说,如果您询问如何创建盐,听起来您正在使用自己的散列方法,这可能具有教育意义,但通常不推荐。

相反,使用现有的哈希(例如 PBDKF2 或 bcrypt)(甚至更好,正如 CBHacking 在评论中正确建议的那样,scrypt 或 Argon2)。您不仅会自动继承他们现有的加盐方法(这已经足够了),而且您的实验将与密码存储最佳实践保持一致……这可能是更好的实践。

2018-04-03更新:Steve Thomas (sc00bz)在这里提出了一个很好的观点,即 Argon2 和 scrypt 在以通常被认为与大规模身份验证兼容的速度(<0.1 秒)使用时实际上对防御者来说更糟,而对于防御者来说更好速度与单个文件加密兼容的防御者(1 到 5 秒)。(这意味着从 0.1 秒到 1 秒的差距可能很有趣,并且需要针对您的特定环境进行测试)。换句话说,他的断言是,如果您尝试将 Argon2 或 scrypt 调整到 <0.1s 的速度,则结果对破解的抵抗力低于 bcrypt 在这些速度下的抵抗力。

在同一个线程中,Aaron Toponce 还提出了一个很好的建议,通过使用bcrypt(base64(sha-256(password))). (另请参见 Thomas Pornin 的类似答案需要 base64 的原因也很有趣——不要忽略它。

因此,如果您的用例是可扩展的、具有快速身份验证体验的防破解身份验证,bcrypt(base64(sha-256(password)))这可能是一个好方法。(并且您需要将 bcrypt 的工作因子调整为适合您的身份验证速度窗口的最大值)。如果您的用户可以容忍等待一秒或更长时间进行身份验证,Argon2i 或 scrypt 可能会更好。请注意,随着硬件功能的提高,相对性能会随着时间的推移而发生变化——因此每 X 个月增加一次新哈希的 bcrypt 工作因子(如 Dropbox 所做的那样)将允许该方法随着时间的推移适应未来的功能。

更新 2019-09-01事实证明,将较快的哈希包装在较慢的哈希中而不先对较快的哈希进行加盐/加盐是危险的,因为可以针对来自另一个来源(例如另一个泄漏)的快速未破解的未加盐哈希进行批量测试包装散列,而不必先破解那些更快的散列然后可以在单独的作业中以更高的速率攻击更快的哈希值。所以我上面的建议应该更新为 bcrypt(base64(sha256(password.salt))).

使用电子邮件地址而不是生成随机值没有任何优势。无论如何,您必须像随机盐一样存储它,否则用户永远无法更改电子邮件地址。

全局唯一性不是必需的,您不需要保证唯一性,但是盐的全局唯一性越多越好。128 位盐 (BCrypt) 的可能组合是 3E38。即使您每秒生成 1000 个盐,人们预计大约需要 6E8 年才能等待 50% 的重复机会。

正如 Royce 已经提到的,今天的算法已经为您生成了盐,并将其以明文形式存储在生成的哈希字符串中,因此无需在数据库中进行特殊处理(哈希只需 1 个字段)。

使用电子邮件地址时,攻击者可以预先计算某些感兴趣的电子邮件的彩虹表。

虽然缺点在实践中不是致命的,但根本没有优点,那么为什么要选择更复杂和更不安全的方法来生成盐呢?使用现代密码哈希函数,你就很好了。

如果不是说盐“需要”是全球唯一的,而是说如果它们是最佳安全性,那么这个主题就会变得更加清晰。

考虑以下简单的攻击模型:攻击者获得n密码条目,并且他们有资源进行m总体测试。现在考虑极端情况:

  • 如果密码未加盐(或所有密码都具有相同的盐),则m可以根据所有n条目检查每个计算。这意味着他们可以测试m * n用户/密码假设。
  • 如果所有密码都用唯一的盐加盐,则每个m计算只能针对 1 个条目进行检查。这意味着他们只能测试m用户/密码假设。

如果一些但不是所有的盐是重复的,攻击者就会得到介于两者之间的东西,与不同盐的数量成正比。但这并不意味着加盐在盐复制上会发生灾难性的失败,而是它的有效性会线性下降。

由于足够大的随机盐通常很容易实现并实现全局唯一性,几乎可以忽略不计,因此几乎没有理由不这样做。

随机盐有另一个重要特性,martinstoeckli 对您链接的问题的回答指出:攻击者无法提前预测您将使用什么盐。您使用电子邮件地址的提议不符合该标准。