「密码该怎么存」这件事,网上的说法多到互相矛盾:有人说 bcrypt 够了,有人说必须上 Argon2,有人说要三个月换一次,有人说换了反而更糟。与其在论坛里吵,不如直接抄标准答案——OWASP 的《Password Storage Cheat Sheet》是这一领域引用最广的权威清单,下面把最硬、最能直接落地的几条摘出来。
一、算法选择:Argon2id 是第一梯队
OWASP 给出的优先级里,Argon2id 排在第一位,官方推荐的最低配置是:
m = 19456 (19 MiB 内存)
t = 2 (迭代 2 次)
p = 1 (并行度 1)
三个参数各管一件事,理解它们就知道了为什么它比哈希「贵」:
m(内存)是抗 GPU 的核心——显卡最缺的就是显存带宽;t(迭代)拉长单次计算时间,抬高暴力破解成本;p(并行度)决定能同时吃几个核,服务端一般保持 1 即可。
排在第二梯队的是 scrypt(N=2^17, r=8, p=1),如果环境不支持 Argon2 再考虑它。
二、bcrypt 的两个坑
bcrypt 至今仍是可接受的选择,但用它必须知道两件事:
- work factor 不能低于 10——这是官方给的底线,低于此值在现代硬件面前形同虚设;
- 输入上限 72 字节,超出部分被静默截断。这条最阴险:
密码 + 后面随便加什么都能通过验证,等于把有效密码长度砍到了 72 字节。
绕过截断的标准做法是先做一次定长摘要再交给 bcrypt:
base64( SHA-256( password ) ) → bcrypt( ... )
这样无论原密码多长,送进去的都是固定不超过 72 字节的串。
三、参数必须跟着哈希一起存
算法、work factor、盐、成本参数——全部要随哈希一起持久化。好消息是主流库(Argon2 的 PHC 格式、bcrypt 的 $2a$11$...)天生就是自描述字符串,参数直接写在哈希里,不需要你另建字段。这也是为什么「以后想调高成本」是可行的。
四、登录成功的那一刻,顺手升级
这是整份文档里最容易被忽略、收益却最高的一条:
当用户正确登录、你手上正好有明文密码时,检查一下存着的哈希是不是还在用旧参数;如果是,立即用新参数重新哈希并存回去。
它的妙处在于:不需要强制任何人改密码,老用户的哈希会随着他们日常登录,无声无息地全部升级到新标准。
五、不要做的事
- 不要强制周期性更换密码。官方明确不支持这种做法——它带来的是可预测的弱化(
Spring2026!→Summer2026!),而不是安全; - 不要用「安全问题」做二次验证。母亲的娘家姓这类答案,往往比密码更容易被查到;
- 不要自己发明加密方案,也不要拿 MD5/SHA-1/SHA-256 裸哈希当密码存储。
另外两条值得加进注册流程:对照已泄露密码库(如 Have I Been Pwned)拒绝 Weak 密码,以及限制密码长度上限(避免超长输入造成 DoS)。
六、出处
- OWASP Cheat Sheet Series — Password Storage Cheat Sheet
https://cheatsheetseries.owasp.org/cheatsheets/Password_Storage_Cheat_Sheet.html
七、在自家服务器上的印证
这份备忘单不是纸上谈兵——本站这台服务器跑的几套服务,恰好各用了其中一种:
- Vaultwarden:管理令牌用 Argon2id 的 PHC 字符串(
$argon2id$v=19$m=65536,p=4,t=3$...),一眼就能读出内存 64 MiB、4 路并行、3 次迭代——正是「参数自描述」的活例子; - WireGuard 面板:密码哈希由容器内的
argon2库生成; - 日志面板:用的是 bcrypt,哈希前缀
$2a$11$里的11就是 work factor,刚好卡在官方要求的 ≥10 线上。
凡是自己部署过一遍的人都会有同感:这些参数不是可以随便填的,它们就是你面对离线爆破时唯一的防守纵深。
评论