2018 年,推荐的存储密码的哈希是什么:bcrypt、scrypt、Argon2?

信息安全 密码 哈希 bcrypt 加密 氩2
2021-08-17 03:40:42

关于选择散列函数有很多问题,包括如何安全地散列密码?或者是否有比 bcrypt 和 scrypt 更现代的密码散列方法?,有非常详细的答案,但其中必须有相当多的日期

共识似乎是:

  • bcrypt 是个不错的选择
  • scrypt 应该是一个更好的选择,但在当时,它还是有点新,所以需要等待,看看它是否经得起时间的考验

Argon2 现在是 Password Hashing Competition 的获胜者,但它肯定还是很新的,所以当时适用于 scrypt 的相同论点现在可能适用于它。

问题:

  • bcrypt 仍然是一个不错的选择吗?
  • scrypt 现在是一个不错的选择吗?
  • Argon2 已经是一个不错的选择了吗?

基本上,今天,对于一个带有密码的普通系统,应该更喜欢哪种密码散列函数?对于那些有参数的函数,它们应该是什么?

编辑

请注意,即使问题与如何安全地散列密码几乎重复?,如上所述,该问题的大多数答案可以追溯到 2010-2013 年,最新的相关更新可以追溯到 2016 年从那以后情况显然发生了变化,我正在寻找的是对这些优秀答案的更新。如果您认为它更有意义,请随意回答该问题的更新并关闭此问题,但请不要在这里或那里没有最新答案就关闭此问题。

1个回答

截至 2021 年,Argon2id 是首选的密码存储功能。理想情况下,您应该使用 libsodium 之类的包装器,它提供基于 Argon2id 的密码存储功能并自动选择合理的硬度因子。

以下建议写于 2018 年。


我不建议将 bcrypt 用于输入值是人工生成的令牌(例如密码)并且离线破解在威胁模型中的新设计。当您考虑到如今的商用硬件有多强大时,缺乏内存硬度是一个严重的问题。虽然缺乏任何主要的基于 bcrypt 的加密货币并没有吸引该算法的 FPGA 或 ASIC 挖掘实现,但仍然有人对使用混合 ARM/FPGA SoC 攻击 bcrypt 感兴趣,例如2014 年的这篇论文归根结底,缺乏记忆硬度是现代设计的一个重大问题。

scrypt 将记忆硬度作为其设计的一部分,但它有一些不足之处。首先,有很多基于 scrypt 的加密货币,这为商品 FPGA 和 ASIC 挖掘解决方案吸引了相当大的市场,这些解决方案可以重新用于破解。此外,scrypt 的内存硬度和迭代次数都与单个标量成本因子相关联。这使得很难根据您自己的威胁模型定制 scrypt。我推荐 scrypt,它是您使用的语言或框架中最简单的密码存储选项,例如,如果它已经是保护用户密码的内置选项。

最终,我总是推荐 Argon2 作为首选,原因如下:

  1. 它已经存在了一段时间——它在 2015 年赢得了PHC。已经有不少论文研究了 Argon2 的安全证明,还有更多研究在专用硬件上加速算法的潜在方法。到目前为止,它已经很好地经受住了审查。
  2. 有C、Erlang、Go、Haskell、JavaScript、Java、Lua、OCaml、Python、R、Ruby、Rust、C#(框架和核心)、Perl 和 Swift 的开源实现和绑定
  3. Argon2 是围绕 AES 密码构建的,大多数现代 x86_64 和 ARMv8 处理器都实现了 AES 指令集扩展。这有助于缩小预期系统和专用破解系统之间的性能差距。(编辑,2019 年 2 月:似乎 Argon2 的较新版本可能与硬件扩展中的 AES 实现不兼容。请参阅评论以进行讨论)
  4. Argon2 特别能抵抗超过三分之一内存的排名权衡攻击,这使得在 FPGA 上进行廉价加速变得更加困难。这是因为基于 FPGA 的破解解决方案大多受到内存带宽的限制,而在 Argon2 的设计中,攻击者必须吞下大量增加的计算时间才能降低内存带宽需求,从而使权衡效率低下。您可以在Argon2 论文的第 5.1 节中阅读更多相关信息,有关 scrypt 的信息可在论文“Tradeoff Cryptanalysis of Memory-Hard Functions”的表 6(第 5 节下)中进行比较
  5. Memory-hardness 和 CPU-hardness 参数可单独配置,以及并行度因素。这使您可以更好地定制与您的用例绑定的安全性,例如具有中等 CPU 能力和大量 RAM 的服务器。

正如您所指出的,您选择的参数很重要。scrypt 没有给你太多选择,所以我建议在这种情况下根据时间(例如 1500 毫秒的处理时间)选择成本因素。

对于 Argon2,您有更多的选择,而不仅仅是参数。事实上,Argon2 有三种不同的实现方式,称为 Argon2d、Argon2i 和 Argon2id。第一个是 Argon2d,它的计算成本最高,并且对内存带宽有限的 GPU、FPGA 和 ASIC 的加速具有抵抗力。然而,由于 Argon2d 的内存访问依赖于密码,泄漏有关内存访问信息的侧通道攻击可能会泄露密码。正如其后缀所暗示的那样,Argon2i 选择独立于密码的内存地址。这降低了它对 GPU 破解的抵抗力,但消除了侧通道攻击。Argon2id 是一种混合方法,其中第一遍使用 Argon2i(独立)方法,随后的遍使用 Argon2d(相关)方法。

只要有可能,您应该使用 Argon2id 实现。但是,这并不总是可用的。对于您正在保护服务器上的密码并且您的威胁模型认为内存访问侧信道攻击不太可能发生的情况(根据我的经验,这是大部分时间),您可以使用 Argon2d。如果内存访问侧信道攻击被认为是潜在风险,例如在多租户系统中,不受信任或不太受信任的用户在执行 Argon2 散列的同一系统上运行代码,那么 Argon2i 可能是更好的选择。

简而言之:如果可以,请使用 Argon2id,在几乎所有其他情况下使用 Argon2d,如果您确实需要内存侧通道攻击抗性,请考虑使用 Argon2i。

对于参数,唯一的硬性规则是 Argon2i,由于其相对于其他选项的弱点,必须对其进行特殊处理。具体来说,由于对 Argon2i 的实际权衡攻击,迭代次数必须为 10 或更多。

您应该根据自己的用例和性能要求调整参数,但我相信以下是 Argon2id 和 Argon2d 可接受的默认值:

  • 512MB 内存
  • 8 次迭代
  • 平行度系数为 8

这个速度取决于你的处理器,但我在我的系统上达到了大约 2000 毫秒。

对于 Argon2i,您必须将迭代次数增加到至少 10 次,这可能需要您出于性能原因降低内存因子。这是尝试避免使用 Argon2i 的另一个原因,除非您绝对需要它对内存访问侧通道的抵抗力。