bcrypt
bcrypt 是基于 Blowfish key setup 的自适应 password hashing scheme,以指数 cost factor 提高 CPU 计算成本并内含 salt;它成熟且广泛部署,但有 72-byte 输入上限且不是 memory-hard,新系统通常优先 Argon2id。
[!info] related notes
- 所属 MOC: 安全 MOC
- Password Storage: Password Storage & Verification
- Salt/Pepper: Salt vs Pepper
- 现代替代: Argon2id
- 兼容方案: PBKDF2
bcrypt
一句话定义
bcrypt 是经典 adaptive password hashing scheme。
它把:
password + salt + cost factor → stored bcrypt verifier
并让 cost 随时间提高。
核心优势
bcrypt 的历史价值包括:
- 为 password hashing 专门设计;
- 每个 hash 包含 salt;
- cost 可调;
- 实现成熟;
- 跨语言生态广泛。
它远好于:
SHA-256(password)
这类快速 hash 方案。
Cost Factor
bcrypt 的 cost 通常写成:
10
12
14
它不是“执行 10 次”。
计算工作量大致按:
2^cost
增长。
所以 cost 增加 1,计算成本大约翻倍。
72-Byte Password Limit
bcrypt 的一个关键边界:
大多数 bcrypt implementation 只处理 password 的前 72 bytes。
注意是:
bytes
≠ characters
UTF-8 中文、emoji 等字符可能占多个 byte。
所以不能简单说“72 个字符”。
不同 library 对超长输入可能:
- truncate;
- reject;
- behavior differs。
应用必须明确目标 library 的行为。
Pre-hashing 风险
有人为了绕过 72-byte limit 会做:
SHA-512(password) → bcrypt
这种做法若设计不正确,可能产生 password shucking 等问题。
如果确实必须 pre-hash,应使用经过明确安全分析的方案,例如 keyed HMAC-based pre-hash,并严格遵循目标库/OWASP guidance。
更简单的新系统方向通常是:
直接使用 Argon2id。
Salt
bcrypt hash string 已经包含:
- version;
- cost;
- salt;
- hash output。
因此使用成熟 bcrypt API 时,不应该自己再手工生成/拼 salt。
bcrypt 不是 Encryption
bcrypt output 不应该“解密”。
登录验证:
candidate password
→ bcrypt compare
→ true / false
如果业务需要恢复原始 secret,那是另一类加密设计,不是 password verifier。
bcrypt vs Argon2id
bcrypt:
- CPU-cost oriented;
- mature;
- 72-byte limit;
- legacy deployment 大量存在。
Argon2id:
- memory-hard;
- 参数更丰富;
- 更适合现代 password-cracking hardware threat。
OWASP 当前把 bcrypt 放在:
legacy system / Argon2id or scrypt unavailable
的位置,而不是新系统首选。
Existing Systems
已有 bcrypt system 不需要因为“不是 Argon2”立刻强制所有用户重置密码。
可以:
bcrypt verifier
→ successful login
→ Argon2id rehash
→ replace stored verifier
逐步迁移。
Pepper
bcrypt 也可以配合 pepper。
但不要把 pepper 直接放进数据库。
如果为了支持长 password 做 pre-hash,OWASP 还特别提醒应考虑 keyed pre-hash 方案,避免泄漏的中间 hash 被用来 password shucking。
DoS
cost 太高会提高服务器 login CPU cost。
仍然需要:
- rate limit;
- concurrency protection;
- benchmark。
cost 不是越大越好。
常见错误
cost=12 永远安全
错误。它只是某个时代/硬件下的参数选择。
72 character limit
错误。关键是 72 bytes。
bcrypt 自带 salt,所以数据库泄漏就没事
错误。攻击者仍可逐个 offline guess。
bcrypt 可以解密
错误,它是 password verifier scheme。
学习检查
- bcrypt cost=12 为什么不是“循环 12 次”?
- bcrypt 的 72-byte limit 为什么对 UTF-8 密码尤其重要?
- 为什么成熟 bcrypt API 不需要自己管理 salt?
- bcrypt 与 Argon2id 最核心的攻击成本模型差异是什么?
- pre-hashing bcrypt 为什么可能引入 password shucking?
- 已有 bcrypt 系统如何平滑迁移到 Argon2id?
- 为什么提高 bcrypt cost 不能替代 login rate limiting?