我应该如何为我的密码哈希函数选择难度系数?

信息安全 密码 哈希 bcrypt 加密 pbkdf2
2021-08-26 23:00:32

假设我正在正确地进行密码散列并使用 bcrypt、scrypt 或 PBKDF2,我应该如何选择合适的难度系数?即 bcrypt 的轮次,PBKDF2 的迭代和 scrypt 的 maxtime,maxmem 或 maxmemfrac。

还要假设最坏的情况会发生,并且我的用户的哈希和盐(以及任何应用程序的盐或胡椒。你知道......最坏的情况。)将意外或故意泄露。

我需要选择一个值:

  1. 对我来说很容易。
  2. 对于攻击者来说太难了。

第一部分相对容易。如果我选择足够多的轮次使 bcrypt 花费 0.5 秒,我可以确定我的用户在登录时不会看到明显的减速。(无论如何,在 Web 应用程序中,0.5 秒并不是很长的时间。)我还知道通过测试该函数的循环,我每分钟可以处理比我目前看到的更多的登录。如果我获得的登录率增加,我可以减少轮数并在每个用户登录时迁移用户,或者我可以等待更好、更便宜的硬件。当我在升级周期中自然变得更好、更便宜的硬件时,我可以增加轮数来弥补。

更难回答的问题是对攻击者来说有多难。当然,这取决于特定攻击者的密码值,但对于这个问题,除了这些用户/密码组合中的大多数将在其他实际有价值的站点上工作这一事实之外,假设没有任何特殊价值。

如果我将 bcrypt 轮数更改为现在需要 0.01 秒而不是 0.5 秒,这是否改变了攻击者的等式,因此现在暴力破解密码的价值超过了暴力破解它的成本?我怎么知道它有没有?

基于了解以下内容,这似乎很容易计算:

  1. 一个通用的用户名/密码对值多少钱。
  2. 用 $difficulty_factor 暴力破解 $hash_function 的散列需要多少成本。

由于 scrypt 被设计为内存硬而不是 CPU 硬,因此 2. 的答案会因算法而异。随着 CPU/GPU 速度增加或 RAM 价格下降,这不是线性加速。

有没有一个地方可以找到随着新硬件可用而更新的上述信息?

到目前为止,我找到的关于密码价值的最佳资源是 Brian Krebs 的博客文章,例如this onethis one对于每秒破解的哈希,这是DEFCON 的“如果可以的话,请破解我”竞赛每美元破解的哈希值会很好。

请在您的答案中忽略这些算法中的任何算法缺陷。如果找到其中一个,我会简单地切换到其他替代算法之一。我认为,如果在其中任何一个中发现缺陷,它将遍布安全新闻。


刚刚在 Crypto.SE上从定义 scrypt的论文中找到了这张表

一年内破解密码的估计硬件成本表。

我只需要每年更新该表即可。

3个回答

不幸的是,种类繁多的硬件会阻止您构建您想要的表,除非您首先调查所有现有的硬件架构以及该架构的最佳 bcrypt/scrypt/PBKDF2实现甚至 scrypt 文章中的表格也不是您想要的:它没有告诉您攻击者会花费多少;它告诉攻击者使用 scrypt 设计者在写这篇文章时想到的硬件和软件要花多少钱

顺便说一句,这样的估计并不能很好地扩大规模。如果我是一名攻击者,在可用硬件的情况下面临估计为 100 亿美元的攻击成本,我会首先投资 10 亿美元来构建一个基于 ASIC 的定制系统,该系统会更快地完成这项工作。PC擅长进行伪随机 RAM 访问,但不是最好的硬件,因为 PC 中有很多其他组件,它们对攻击毫无用处。

至少,对于 PBKDF2,由于计算映射到没有内存访问问题的底层哈希函数,您可以使用现有的哈希函数基准来获得一个想法(例如这些)。


话虽如此,一切都没有丢失。你不会得到准确的攻击成本估计,但这并不意味着你所能做的就是哀号、萎缩和死亡。第一种实用的方法是将迭代计数设置得尽可能高:将其设置为不会使正常登录过程慢得不能忍受的最大值。这样,您将不知道您的安全性是否良好,但它会尽可能好这是一个安慰。

其余的工作将在用户方面。毕竟,密码散列的难度因素是为了抵消摩尔定律。然而,充其量,这是密码熵攻击者耐心之间的匹配:

  • 攻击者的优势是他比较有钱,可以购买专用硬件,并且有耐心:他可以花一小时,也许一天来破解一个高价值的密码;而用户在登录时不会容忍等待超过一秒钟。
  • 防守方的优势是密码熵

考虑到攻击者的效率因子为 1000(专用硬件,投入更多的钱)和耐心因子 86400(攻击者希望在一天内成功,用户不会等待超过一秒),然后是密码如果防守方要赢得比赛,熵必须超过 8600 万(也就是多于 26 位)。要提高密码熵,只有一种方法:教育、教育、再教育。不要试图强制执行“密码规则”,它们会激怒用户而不是制作强密码。相反,提供一个非强制性的密码生成器按钮,该按钮生成具有 40 位熵的密码,并向用户解释使用该按钮将是一个非常好的主意。

使用您的目标硬件,我会选择一个导致算法花费大约 1/10 秒的成本。在登录尝试失败后实施延迟。暴力破解任何未精心选择的密码(例如,用户名、站点名称、“密码”)是不划算的。您选择的实际值将取决于您的目标硬件。

  1. 如果密码很弱,算法速度无关紧要。
  2. 如果密码在字典里,你几乎立刻就被搞砸了
  3. 如果密码是由 JtR 或 Hashcat 中包含的规则生成的,那么您稍后会被搞砸;)

除此之外,您存储了多少用户/密码?如果您只保护一个帐户(想想一个只有 root 帐户的服务器),那么加盐是没有意义的。

您多久被迫更改一次密码?如果密码的难度会迫使攻击者进入一个完整的字符集、长密码暴力破解,那么你可以做出一个不错的近似:NumberOfCombos/CrackSpeed=TimeToCrack

因此,如果您有一个 6 字符长、完全随机的可打印 ASCII(95 个符号),您可以每秒破解 100 个字符,那么您有 95^6/100=233 年的时间来破解整个密钥空间。

但是,如果您使用一些快速的算法(我的 GPU 以 80 亿/秒的速度破解单个、单轮、未加盐的 MD5),并向其投入一些体面的硬件,那么您可以在大约 90 分钟内破解整个 6 字符键空间秒。在同一个字符集上转到长度 7 会将破解时间延长到 > 2 小时,长度 8 将其延长到 9 天。因此,如果您每 90 天更改一次密码,那么攻击者就有足够的时间来破解并使用长度为 8、字符集为 95 的密码。

规则很简单,你制作的字符集越大,密码越长,keyspace 将以荒谬的速度增长。现代硬件和软件使破解速度非常快,但您可以使用盐/算法减轻威胁。真正的杀手是当你没有强迫攻击者进入暴力场景时。字典/规则/排列/多词组合攻击在查找非随机密码方面非常有效。