作为密码破解者,我鼓励我的所有目标都使用这种技术。😉
这(可以理解!)似乎是个好主意,但事实证明,针对现实世界的攻击,用 bcrypt包装未加盐的哈希显然比简单地使用 bcrypt 弱。
(编辑:首先,要明确一点,比单独好得多bcrypt(md5($pass))
-所以md5($pass)
这一切都不应该意味着这个方案应该保持原样。)
从实际攻击的角度来看,包装未加盐的哈希是有问题的,因为攻击者可以这样做:
- 从泄漏中获取现有的 MD5 密码 -甚至是尚未破解的 MD5
- 在用尽简单的攻击后,将这些 MD5 作为“词表”运行在您的
bcrypt(md5($pass))
语料库中,以识别具有已知 MD5 的未破解 bcrypt
- 以更高的速度破解bcrypt 之外的那些 MD5
是的 - 你必须首先发现 bcrypt 中的 MD5。但关键是MD5 可以是其他未破解的 MD5,恰好存在于其他泄漏中,然后您可以以大幅提高的速度对其进行攻击。
这不是理论上的攻击。高级密码破解者一直使用它来成功破解 bcrypt 哈希,否则攻击者将完全无法获得。
这种攻击的工作原理对于非专家来说是非常不直观的,因此我强烈鼓励怀疑者尝试真实世界的场景以了解它是如何工作的:
- 使用 MD5 散列 6 个字符的随机密码。
- 假设这个 MD5 已经出现在其他一些泄露的密码列表中,证明它在某个时候被用作密码。
- 尝试用蛮力直接攻击MD5。
- 将 MD5 包裹在 bcrypt 中,尝试直接暴力破解。
- 攻击相同的 bcrypt-wrapped MD5,但这次假装你还没有破解 MD5,而是使用包含你的 MD5 的泄露 MD5 的“字典”。
- 一旦你“发现”你手头有一个 MD5 在你的一个 bcrypt 中,攻击 MD5,然后将生成的明文传递给你的 bcrypt(md5($pass)) 攻击。
再一次,非常不直观,所以玩它(不要因为理解它需要工作而感到难过;在我最终得到它之前,我与 Jeremi Gosney连续一个小时激烈地反对它!)
我不相信这种技术有一个“官方”的名称,但我一直称它为“哈希去壳”或只是“去壳”。
因此,根据用例,包装 bcrypt 具有吸引力的原因是完全可以理解的(例如,超出 72 个字符的 bcrypt 最大值,尽管由于其他原因,这可能会很棘手,包括“空字节”问题),或者迁移现有的哈希。
因此,如果有人需要在 bcrypt 中包装散列,那么对于这个弱点的缓解措施现在应该很清楚了:您的内部散列绝不能出现在任何其他可能对攻击者可用的密码存储系统中。这意味着您必须使内部哈希值全局唯一。
对于您的特定用例 - 您需要保留现有哈希 - 有几个选项,包括:
- 在您的 Web 或 DB 框架中添加全局胡椒- 因此,这允许您轻松迁移现有的 MD5,但该全局胡椒仍然会被盗(但如果您的网络层与您的 DB 层/身份验证分开,这可能是可接受的风险,YMMV);
bcrypt($md5.$pepper)
- 使用HSM基础架构添加全局辣椒(以一种连网络应用程序都看不到的方式存储辣椒,因此不会被盗)
- 添加额外的每个哈希盐(但你必须以某种方式将其存储在哈希之外,这开始变得棘手并濒临“滚动你自己的加密”领域);
- 在 bcrypt 层内使用慢速、加盐的哈希算法或 HMAC 对 MD5 进行哈希处理(不推荐,我什至没有资格就如何正确完成提出建议,但这是可能的 - Facebook 正在这样做,但有些非常聪明人们设计的);
有关更多详细信息,包括一些特定场景来说明为什么它比单独的 bcrypt 弱,请参阅我的超级用户回答here,这个关于“预散列”密码的 OWASP 指南,它更清楚地支持我的断言,以及Sam Croley讨论的这个谈话技术。
一般来说,密码升级可能很棘手;请参阅 -这个答案和Michal Špaček关于密码存储升级策略的页面。