大家好,我是程序员柏风,AI 最全的 Vibecoding 学习地图 http://coderoadmap.cn 作者。
密码哈希
数据库泄露时,明文或可逆加密 的密码会直接变成用户在其他网站的复用密码。密码哈希 的目标是:服务器只存 不可逆的指纹,登录时对用户输入做同样运算再比对。后端必须会用 慢哈希 + 唯一盐,并明白 SHA-256 单独用于密码 为什么不够。
学习目标
- 区分 哈希、加盐、 pepper、加密
- 选用 bcrypt / scrypt / Argon2 等密码专用算法
- 在 Spring 栈对接
PasswordEncoder,避免自造 crypto
不要做什么
| 做法 | 问题 |
|---|---|
| 明文存储 | 泄露即完蛋 |
| MD5 / SHA-256 无盐快哈希 | GPU 彩虹表秒破 |
| 自己设计「先 MD5 再 SHA1」 | 非专家极易出错 |
| 同一盐全库共用 | 削弱防护 |
| 可逆 AES 存密码 | 密钥泄露 = 全部密码还原 |
密码验证是单向的——忘记密码应 重置,不应「解密发邮件」。
盐(Salt)与 Pepper
- Salt:每用户随机,与哈希 一起存 DB;防彩虹表、同密码不同摘要
- Pepper:全站秘密,放 环境变量 / HSM,不进 DB;泄露 DB 仍缺 pepper
stored = bcrypt(password + pepper, salt) // pepper 可选,bcrypt 内置 salt 处理
Spring Security 的 BCryptPasswordEncoder 已把 salt 编进 $2a$10$... 字符串。
算法选型
| 算法 | 特点 | Spring 支持 |
|---|---|---|
| bcrypt | 成熟、自适应 cost | BCryptPasswordEncoder ✅ 默认推荐 |
| scrypt | 内存硬,抗 ASIC | 需额外库 |
| Argon2 | 现代 winner | Argon2PasswordEncoder(Spring 5+) |
| PBKDF2 | 标准、可调迭代 | Pbkdf2PasswordEncoder |
cost / iterations 要随硬件升级调高——不是配一次 forever。
Spring Boot 示例
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder(12); // strength 10–12 常见
}
// 注册
user.setPasswordHash(passwordEncoder.encode(rawPassword));
// 登录
if (!passwordEncoder.matches(rawPassword, user.getPasswordHash())) {
throw new BadCredentialsException("...");
}
永远不要在日志里打 rawPassword。注册与改密接口应 HTTPS(sec-ssl)。
SHA 用在哪、不用在哪
- ✅ SHA-256:文件完整性校验、Git commit、HMAC 构件
- ❌ SHA-256 单轮密码:太快,不适合
- ✅ HMAC-SHA256:API 签名、JWT(配合密钥,见 sb-jwt)
不要把「哈希登录密码」与「哈希文件 checksum」混为一谈。
与认证方式的关系
- Basic 认证:每次传密码,更依赖 TLS
- Cookie / Token:登录成功后 不再重复传密码
- OAuth:密码往往只在 IdP 侧验证,本系统 不应存第三方用户密码(除本地账号体系)
统一账号体系时,密码策略(长度、 breached password 检查)与哈希 同一 Service 维护。
泄露响应
- 强制 全站改密 或下线 reset 流程
- 轮换 session / refresh token
- 调查泄露范围,通知合规
存 bcrypt 能 赢得时间,不是免死金牌——仍要当 incident 处理。
练习
- 用
BCryptPasswordEncoder对同一密码 encode 两次,观察 hash 为何不同 - 解释:为何
matches()不需要你从 DB 拆出 salt - 阅读 sb-security 中 UserDetails 与 PasswordEncoder 接线
小结
密码只存慢哈希 + per-user salt;bcrypt/Argon2,禁止 MD5/裸 SHA。 下一课最简单的 HTTP 认证:Basic。