$2a$ / $2b$ 是 Bcrypt 的版本前缀,
10 是代价因子(210 = 1024 轮)。
Bcrypt 密码哈希生成与校验工具,分为两个面板:
$2a$10$N9qo8uLOickgx2ZMRZoMyeIjZAgcfl7p92ldGxad68LJZdL17lhWy。所有计算都在浏览器本机完成,密码与哈希值都不会上传到服务器。
Bcrypt 由 Niels Provos 和 David Mazières 于 1999 年基于 Blowfish 分组密码设计,最初用于 OpenBSD,如今是应用最广的口令哈希算法之一。
| 项目 | 说明 |
|---|---|
| 设计者 | Niels Provos、David Mazières(1999) |
| 基础算法 | Blowfish(EksBlowfish 变体) |
| 输出长度 | 固定 60 个字符的编码串 |
| 盐长度 | 固定 16 字节(编码后 22 个 Base64 字符) |
| 摘要长度 | 23 字节(编码后 31 个字符) |
| 代价因子 | cost,取值范围 4 – 31,实际常用 10 – 14 |
| 是否可逆 | 不可逆 |
以 $2a$10$N9qo8uLOickgx2ZMRZoMyeIjZAgcfl7p92ldGxad68LJZdL17lhWy 为例:
| 片段 | 含义 |
|---|---|
$2a$ | 算法版本标识 |
10 | 代价因子,实际轮数为 2^10 = 1024 |
N9qo8uLOickgx2ZMRZoMye | 22 个 Base64 字符,表示 16 字节盐值 |
IjZAgcfl7p92ldGxad68LJZdL17lhWy | 31 个 Base64 字符,表示 23 字节摘要 |
| 前缀 | 说明 |
|---|---|
$2$ | 最早的版本,存在已知缺陷,已基本淘汰 |
$2a$ | 修正了长度处理问题,目前最常见 |
$2b$ | OpenBSD 修正了一个 72 字节边界处的溢出缺陷,新实现多输出此版本 |
$2x$ / $2y$ | 历史遗留(PHP 早期实现与 crypt_blowfish 的兼容标记),现代系统一般不再输出 |
本工具使用 hash-wasm 的实现,输出 $2a$ 前缀,可以校验 $2a$ / $2b$ / $2y$ 等各版本哈希串。
cost 每 +1,计算量翻倍。下表为浏览器本机(WebAssembly)实测的参考耗时:
| cost | 轮数 | 参考耗时 | 建议 |
|---|---|---|---|
| 8 | 256 | 约 20 ms | 仅用于测试,强度偏低 |
| 10 | 1024 | 约 70 ms | 默认推荐,兼顾安全与体验 |
| 12 | 4096 | 约 260 ms | 安全要求较高时使用 |
| 14 | 16384 | 约 1 s | 高安全场景,登录会明显变慢 |
| 16 及以上 | 65536+ | 数秒以上 | 一般不建议,容易造成拒绝服务 |
原则:让一次校验耗时落在 100 – 500 毫秒之间。这样正常登录用户几乎无感,而攻击者尝试一次的成本被抬高到无法承受。
Bcrypt 只处理密码的前 72 个字节,超出的部分会被静默忽略:
| 维度 | Bcrypt | Argon2 |
|---|---|---|
| 发布年份 | 1999 | 2015 |
| 抗 GPU 能力 | 一般(只消耗 CPU 时间,不消耗内存) | 强(内存开销可调) |
| 参数维度 | 只有 cost | 内存 m、迭代 t、并行 p 三个维度 |
| 兼容性 | 极好,几乎所有语言与框架内置 | 较好,现代语言多数支持,部分旧环境缺失 |
| 推荐度 | 存量系统首选、新项目可用 | 新项目的首选 |
OWASP 密码存储备忘单的立场是:优先 Argon2id,其次 scrypt,再次 Bcrypt,最后 PBKDF2。但如果现有系统已经用了 Bcrypt 且 cost 设置合理,没有必须迁移的理由。
为什么要给密码加盐?
Bcrypt 可以用来加密文件吗?
同一个哈希串在不同语言里校验结果会不一样吗?
密码和哈希值会被上传到服务器吗?
校验时为什么不需要再填盐值和 cost?
Bcrypt 和 Argon2 该选哪个?
Bcrypt 能解密吗?
$2a$、$2b$、$2y$ 有什么区别?
Bcrypt 的 72 字节限制是什么?
代价因子 cost 应该设多少?
Bcrypt 的哈希值为什么每次都不一样?
Bcrypt 是什么?