跳转到主要内容

bcrypt

本文约需 2 分钟阅读

bcrypt 是 Niels Provos 与 David Mazières 于 1999 年设计的、以 Blowfish 加密为基础的密码哈希函数。其特点是通过调整成本因子 (工作因子) 即可使计算成本呈指数级增长的设计,能够随着硬件性能的提升而提高安全强度。它被广泛使用已超过 25 年,即便在Argon2 已经出现的今天,仍是在 OWASP 推荐列表中位列第二的高可靠算法。

历史背景

在 bcrypt 出现之前,Unix 系统使用基于 DES 的 crypt 函数进行密码哈希。然而到了 1990 年代后期,由于 CPU 的高速化,crypt 的计算成本变得不足,字典攻击和暴力破解攻击成为现实的威胁。Provos 与 Mazières 作为 OpenBSD 项目的一部分设计了 bcrypt,确立了「即使在未来的硬件上也能保持安全」的自适应哈希函数这一概念。这种设计思想后来也被 scrypt 和 Argon2 所继承。

成本因子的工作原理

bcrypt 的成本因子以 4 到 31 的整数指定,内部上会进行 2 的成本次方次的迭代处理。将成本因子增加 1,计算时间约增加一倍。

成本因子迭代次数处理时间参考用途
101,024约 100 ms最低标准
124,096约 400 msOWASP 推荐 (2025 年)
1416,384约 1.5 秒高安全环境

在实务中,应选择登录处理延迟仍处于可接受范围 (通常为 250 ms - 1 秒) 内的最大成本因子。建议根据服务器的 CPU 性能定期重新评估并提高成本因子。

盐值的自动生成与存储格式

bcrypt 会自动生成 128 位的盐值,并与哈希值一起作为一个字符串保存。开发者无需单独实现盐值的生成或管理,这是其在实务上的一大优势。

$2b$12$LJ3m4ys3Lg7Ey6yGqV8sZeKxYBCfGJZiNL5.mDHbgA7cWyPCkxbC6
├ $2b$ ... 算法版本
├ 12$ ... 成本因子
├ LJ3m4ys3Lg7Ey6yGqV8sZe ... 盐值 (22 个字符)
└ KxYBCfGJZiNL5.mDHbgA7cWyPCkxbC6 ... 哈希值 (31 个字符)

与 Argon2 的比较

bcrypt 与 Argon2 最大的区别在于是否为内存困难型。bcrypt 是 CPU 受限的函数,计算时不需要大量内存。因此,对于在拥有数千核心的 GPU 上并行执行哈希计算的攻击,它的抗性不如 Argon2。对于新系统,Argon2id 是首选;但对于已经采用 bcrypt 的系统,只要成本因子设置得当,并不需要立即迁移。如需迁移,常见做法是在下次登录时重新哈希。密码存储的整体设计在安全的密码管理指南中进行了说明。

72 字节限制的注意事项

bcrypt 存在输入密码会在 72 字节处被截断的限制。在 UTF-8 编码下,一个日文字符会占用 3 字节,因此仅由日文组成的密码实际上限为 24 个字符。若混用英文字母和数字,最多 72 个字符有效,超出部分会被忽略。为规避这一限制,有一种先用 SHA-256 对密码进行哈希再传给 bcrypt 的做法,但由于存在空字节问题等陷阱,需要谨慎实现。在设计密码策略时请考虑这一限制。密码安全相关书籍 (Amazon)可学习实现的细节。

常见误解

「bcrypt 太旧所以危险」这种认知并不准确。bcrypt 本身尚未发现致命漏洞,只要以适当的成本因子 (12 以上) 运行,截至 2025 年仍能提供足够的安全性。真正成为问题的是成本因子过低 (低于 10) 的情况,或继续使用包含库漏洞的旧实现的情况。密码哈希的历史演变在密码的历史与文化一文中也有介绍。关于加密的基础知识,请参阅加密的基础

相关术语

这篇文章对您有帮助吗?

XHatena