使用 PBKDF2-SHA256 时推荐的迭代次数?

信息安全 密码学 密码 应用安全 哈希 pbkdf2
2021-08-13 22:33:18

我很好奇是否有人在确定使用 PBKDF2(特别是 SHA-256)时有多少次迭代“足够好”时有任何建议或参考点。当然,“足够好”是主观的,很难定义,因应用程序和风险状况而异,今天的“足够好”明天可能还不够“好”……

但问题仍然存在,业界目前认为“足够好”是什么?有哪些参考点可供比较?

我找到的一些参考资料:

  • 2000 年 9 月 - 推荐 1000 多轮(来源:RFC 2898)
  • 2005 年 2 月 - Kerberos 5 中的 AES“默认”为 4096 轮 SHA-1。(来源:RFC 3962)
  • 2010 年 9 月 - ElcomSoft 声称 iOS 3.x 使用 2,000 次迭代,iOS 4.x 使用 10,000 次迭代,显示 BlackBerry 使用 1(未说明确切的哈希算法)(来源:ElcomSoft
  • 2011 年 5 月 - LastPass 使用 100,000 次 SHA-256 迭代(来源:LastPass
  • 2015 年 6 月 - StableBit 使用 200,000 次 SHA-512 迭代(来源:StableBit CloudDrive Nuts & Bolts
  • 2015 年 8 月 - CloudBerry 使用 SHA-1 的 1,000 次迭代(来源:CloudBerry Lab Security Consideration (pdf)

对于您如何确定多少次迭代对您的应用程序来说“足够好”,我将不胜感激。

作为附加背景,我正在考虑将 PBKDF2-SHA256 作为用于对具有安全意识的网站存储的用户密码进行哈希处理的方法。我计划的 PBKDF2 盐是:每个用户随机盐(与每个用户记录一起存储在明文中)与全局盐异或。目的是增加暴力破解密码的成本,并避免泄露具有相同密码的用户对。

参考:

  • RFC 2898:PKCS #5:基于密码的加密规范 v2.0
  • RFC 3962:Kerberos 5 的高级加密标准 (AES) 加密
  • PBKDF2:基于密码的密钥派生函数 v2
4个回答

您应该在应用程序中使用性能方面可以容忍的最大轮数。轮数是一个减速因素,你使用它是基于在正常使用情况下,这样的减速对你的影响可以忽略不计(用户不会看到,额外的 CPU 成本并不意味着购买更大的服务器,并且很快)。这在很大程度上取决于操作环境:涉及哪些机器,每秒有多少用户身份验证......所以没有一刀切的响应。

广阔的画面是这样的:

  • 在您的系统上验证单个密码的时间是v 。您可以通过选择 PBKDF2 中的轮数来调整此时间。
  • 潜在的攻击者可以收集比你多f倍的 CPU 能力(例如,你有一个服务器,攻击者有 100 台大型 PC,每台都比你的服务器快两倍:这导致f=200)。
  • 普通用户有一个熵为n位的密码(这意味着尝试使用“似是而非的密码”字典来猜测用户密码,平均需要2 n-1次尝试)。
  • 如果平均密码可以在小于p的时间内被破解(这是攻击者的“耐心”),攻击者会发现你的系统值得攻击。

您的目标是使破解单个密码的平均成本超过攻击者的耐心,这样他甚至不会尝试,而是继续专注于另一个更容易的目标。使用上面详述的符号,这意味着您想要:

v·2 n-1 > f·p

p超出您的控制范围;可以估计受用户密码保护的数据和系统的价值。假设p是 1 个月(如果需要超过 1 个月,攻击者不会费心尝试)。您可以通过购买更大的服务器来使f更小;另一方面,攻击者会尝试通过购买更大的机器来使f更大。更糟糕的是,密码破解是一个令人尴尬的并行任务,因此攻击者使用支持通用编程的 GPU 将获得很大的提升所以一个典型的f仍然会在几百的数量级范围内。

n与密码的质量有关,您可以通过严格的密码选择策略以某种方式影响它,但实际上您将很难获得超过 32 位的n值。如果您尝试强制使用更强的密码,用户将开始积极与您抗争,他们会采取一些变通办法,例如重复使用其他地方的密码、在便笺上写密码等等。

所以剩下的参数是v使用f = 200(一个有十几个好 GPU 的攻击者)、一个月的耐心和n = 32,你需要v至少为 241 毫秒(注意:我最初在这里写了“8 毫秒”,这是错误的——这是一天而不是一个月的耐心的数字)。因此,您应该在 PBKDF2 中设置轮数,以便通过单个密码计算它至少在您的服务器上花费那么多时间。您仍然可以使用单核每秒验证四个密码,因此 CPU 影响可能可以忽略不计 (*)。实际上,使用更多的轮数比这更安全,因为,让我们面对现实吧,从普通用户密码中获取 32 位的熵有点乐观。另一方面,没有多少攻击会花费整整一个月的几十台PC来完成破解单个密码的任务,所以也许一天的“攻击者的耐心”更现实,

所以你需要做一些基准测试。此外,只要您的 PBKDF2/SHA-256 实施速度很快,上述方法就可以工作。例如,如果您使用完全基于 C#/Java 的实现,对于 CPU 密集型任务,您将获得典型的 2 到 3 减速因子(与 C 或汇编相比);在上述符号中,这相当于将f乘以2 或 3。作为比较基准,2.4 GHz Core2 CPU 每秒可以执行大约 230 万次基本 SHA-256 计算(单核),因此这意味着,在那个 CPU 上,大约需要 20000 轮才能达到“8 毫秒”的目标。


(*) 请注意,使密码验证更加昂贵也会使您的服务器更容易受到拒绝服务攻击您应该应用一些基本的对策,例如将每秒发送过多请求的客户端 IP 地址暂时列入黑名单。无论如何,您都需要这样做,以阻止在线词典攻击。

在命令行上运行openssl speed以了解消息摘要函数的速度。在我的四核 2.2ghz 沙桥上,我可以每秒计算大约 160 万次 sha256 哈希或每天大约 1450亿次猜测。如果某人的密码在英语词典中并使用了一轮 sha256,那么从磁盘加载单词列表要比遍历列表来破坏散列需要更长的时间。如果您使用数十万轮执行 PKBDF2-SHA256,则需要几分钟才能破解。执行强密码策略 有很大帮助。

真正的答案:你需要燃烧多少时间?

Thomas 的回答提供了有用的基线模型和数据。但他提出的目标对我来说没有意义。一个典型的攻击者在实际入侵站点并获取哈希数据库之前不会知道您的迭代次数。这样做后,他们不会仅仅因为您使用大量迭代计数而继续前进。他们将尝试尽可能多地破解,并且很可能会公开这些哈希值,以便其他人将继续尝试破解它们多年,以提供越来越强大的硬件。因此,“p”和“f”在黑客攻击后很长时间都将继续增加。

此外,真实用户密码并不能通过 32 位熵之类的复杂性度量来很好地建模。文章Reusable Security: New Paper on Password Security Metrics在这方面很有帮助,并记录了我们早就知道的内容:许多用户选择易于猜测的密码,并且有一个长尾。这也意味着如果攻击者足够努力,他们总能找到一些。

我想说一个更有可能的目标是保护尽可能多的用户免于密码被破解。例如, PDF的表 4.2.1显示,如果您在某些攻击活动中设法将攻击者从平均每次哈希 100 万次尝试限制到 500,000 次尝试,您可能会保护 5% 用户的密码(假设混合7 个字符的密码多于 8 个字符以上的密码,从而将破解百分比从 35% 降低到 30%)。当然,曲线的确切形状以及它们在曲线上的位置会有很大差异。

因此,我会选择您可以预算的最大迭代次数,只要它不会延迟真正的用户进行正常登录。随着计算能力多年来的增长,您应该增加价值。

把它当作一个很长的评论。我很好奇这些东西在我的个人笔记本电脑(Thinkpad T460p,Intel i7-6700HQ)上运行得有多快。我知道破解加盐密码有特殊的设备,但如果你有网络服务,你可能没有特殊的硬件。

评价结果

werkzeug.security.generate_password_hash当前 (2019-06-01)的默认值为pbkdf2:sha256:150000.

如您所见,执行时间随着轮数/迭代次数线性增长。这意味着默认值在我的机器上平均需要大约 281 毫秒。

在此处输入图像描述

在此处输入图像描述

sha512,     1 iteration : min:   67.1μs, mean:    72.2μs, max:   310.9μs
sha512, 15000 iteration: min: 38462.8μs, mean: 40291.2μs, max: 44842.4μs
sha256, 15000 iteration: min: 27167.6μs, mean: 28118.0μs, max: 30826.0μs
sha512,  1000 iteration: min:  2636.7μs, mean:  2694.3μs, max:  3579.0μs
sha256,  1000 iteration: min:  1870.7μs, mean:  1888.8μs, max:  2477.0μs
md5,    15000 iteration: min: 21126.2μs, mean: 21864.8μs, max: 23799.3μs
sha512,     1 iteration : min:   23.4μs, mean:    26.9μs, max:    40.6μs
sha512,  1000 iteration: min:  2586.7μs, mean:  2761.1μs, max:  3120.6μs
sha256,  1000 iteration: min:  1823.3μs, mean:  1834.6μs, max:  2008.5μs
sha512, 15000 iteration: min: 38507.9μs, mean: 40210.8μs, max: 47430.3μs
sha256, 15000 iteration: min: 27257.1μs, mean: 28454.0μs, max: 31213.5μs
md5,    15000 iteration: min: 21219.9μs, mean: 21842.4μs, max: 24305.0μs

代码