密码为什么要加密存储?BCrypt 的原理是什么?相比 MD5+盐有什么优势?
- 标签:Spring Security、认证授权、后端
🏛 业务架构师
密码必须加密存储(准确说是单向哈希+盐)的理由:数据库随时可能被拖(SQL 注入、备份泄露、内部人员)——明文密码一泄,攻击者拿它撞库(用户在别处用同一密码),损失放大到用户的其他账户;监管上(个保法、等保)密码明文存储属于重大违规,可直接处罚。
BCrypt 原理:
- 基于 Blowfish 算法改造的可调成本哈希:自带随机盐(每次哈希结果都不同,盐直接编在输出里
"$2a$10$salt+hash",无需单独存盐); - 成本因子(work factor,如 10 = 2^10 轮迭代):可随硬件进步调高——摩尔定律下"算力变便宜"的对抗手段,哈希一次约 100ms,暴力破解一个 8 位密码的成本指数级上升;
- 输出 60 字符定长。
相比 MD5+盐的优势:
| 维度 | MD5+盐 | BCrypt |
|---|---|---|
| 速度 | 微秒级(对攻击者是好事——GPU 每秒可算千亿次) | 慢 5 个数量级(专为"慢"设计) |
| 盐管理 | 要自己生成、存储、防重复盐 | 内置自动盐 |
| 算法抗性 | MD5 已被碰撞攻破、GPU/彩虹表加速成熟 | 专为密码设计,抗 GPU 并行(内存依赖) |
| 可调强度 | 无 | 成本因子随硬件升级 |
业务落地:Spring Security 默认就是 BCrypt(PasswordEncoderFactories.createDelegatingPasswordEncoder())——带版本前缀的委托设计支持未来升级算法(旧密码兼容验证、逐步重哈希)。安全底线三件套:BCrypt 存储、HTTPS 传输、登录失败限流——这套默认配置别去"优化"它。
🏗 系统架构师
密码必须加密存储 = 数据库泄露时的最后防线:明文/可逆加密一旦拖库,全部账户即刻沦陷(且撞库攻击蔓延到用户其他账户);密码学原则——密码不需要"可恢复",只需要"可验证",所以用单向慢哈希。
BCrypt 原理(三层设计):
- 自适应慢哈希:基于 Blowfish 改造,成本因子(cost/rounds)控制迭代轮数——每 +1 轮耗时翻倍(默认 10 ≈ 100ms 量级);硬件进步时调高 cost 保持"慢"——对抗 GPU/ASIC 暴力枚举(单次 100ms,攻击者每秒只能试几十个,而不是 SHA256 的每秒百亿次);
- 内建盐(salt):每次哈希随机生成 16 字节盐,防彩虹表与相同密码同密文(盐嵌在输出里,无需单独存储列);
- 输出自包含:
$2a$10$[salt][hash]——算法版本、cost、盐、密文一个字符串,验证时从密文自身解析参数(升级 cost 只改新密码,老密文按自己的 cost 验)。
相比 MD5+盐 的优势:
- MD5 太快:通用哈希为速度设计——GPU 每秒数十亿次,任何盐都挡不住暴力枚举(盐只防彩虹表,不防穷举);
- 盐的管理成本:MD5+盐要自己处理盐生成、存储、拼接——实现错误率高(盐复用、拼接顺序错);BCrypt 一体化无心智负担;
- 无升级机制:MD5 方案要提高强度要全量重哈希;BCrypt 的 cost 透明内嵌(DelegatingPasswordEncoder 还支持
{bcrypt}前缀多算法共存与迁移)。
架构实践:Spring Security 默认 BCryptPasswordEncoder(cost 10 起步,按硬件调到目标 100ms);同类替代 Argon2(内存困难,抗 ASIC 更强,新系统可选);已有 MD5 存量:登录时透明升级(MD5 验证通过 → 重哈希成 BCrypt 落库),平滑迁移不停机。
💻 全栈开发专家
为什么必须加密存储:数据库泄露(拖库)、内部人员、备份文件流转——明文密码一旦暴露,撞库连带伤害是指数级的。密码存储的铁律是只存「可验证不可还原」的形式。
BCrypt 原理:
- 基于 Blowfish 改造的可调代价函数:内置盐(随机 16 字节)+ 成本因子 cost(默认 10,2^cost 轮);
- 输出自带元数据:
$2a$10$[22位盐][31位哈希]——盐嵌在结果里,无需单独存储; - 慢得恰到好处:cost=10 约 100ms/次——正常登录无感,暴力破解则每猜一次都要 100ms,GPU 也要硬扛;cost 可随硬件升级调到 12/14(未来防暴力能力可持续增强);
- 盐在 BCrypt 内部参与多轮加密(不是简单拼接),对抗彩虹表和 GPU 并行。
相比 MD5+盐的优势:
| MD5+盐 | BCrypt | |
|---|---|---|
| 速度 | 微秒级(GPU 万亿/秒) | 故意慢(百毫秒级) |
| 盐 | 要自己生成/存储/防逻辑错 | 内置、自包含 |
| 抗暴力 | cost 固定,硬件升级=防线失守 | cost 可调,可持续加固 |
| 算法 | MD5 已被密码学界判死刑(碰撞) | 专为密码设计 + 20 年实战 |
Spring 工程实践:
java
@Bean
PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder(12); // 新项目建议 12
}
// 存:encoder.encode(rawPwd) 验:encoder.matches(rawPwd, hashed)升级坑:已有 MD5 存量密码——「入职加密」策略:登录成功时用 BCrypt 重编码更新(DelegatingPasswordEncoder 的 {bcrypt} 前缀方案支持多算法共存渐进迁移)。同类推荐:Argon2(抗 GPU/ASIC 更强,内存困难函数)、scrypt;它们仨都比 MD5/SHA 系强几个量级。