Password Storage - OWASP Cheat Sheet Series
一、为什么要这样存密码?
当我们的应用或数据库一旦被攻破,黑客就能拿到“存储在那儿”的密码信息。为了让他们即使拿到这些数据,也无法轻易还原出用户的真实密码,我们要把密码“加工”成只有单向不可逆的形式(也就是 哈希),而且要让这个加工过程足够“吃资源”,让黑客“猜密码”时变得非常缓慢。
二、哈希(Hash) vs 加密(Encryption)
- 哈希 是把密码“压缩”成一串固定长度的乱码,且无法还原回原文。适合存密码。
- 加密 是可逆的,存后还能解密回原文。适合存地址、信用卡号等,但不推荐用来存密码(除非万不得已要把密码再用来登录其它老系统)。
三、核心防护手段
- 哈希算法要选慢一点的、抗暴力破解的
- 给每个密码加“盐”(Salt):每个用户随机生成一段字符串,放到密码前后一起哈希,这样相同密码也会得到不同的结果,防止大规模“彩虹表”攻击。
- 可选再给所有密码加一个“椒”(Pepper):全局共用的一段秘密,单独存放在安全的地方(比如专门的“密钥保险库”),即使数据库泄露,黑客也拿不到这段“椒”就解不开任何密码哈希。
- 工作因子(Work Factor):控制哈希运算要做多少次、用多少内存。数值越大,验证登录时越慢,但破解时成本也越高。要在安全和性能之间找到平衡,一般让一次哈希耗时不到 1 秒即可。
四、推荐的哈希算法及参数
-
Argon2id(首选)
- 内存(Memory)≈19 MiB,迭代(Iterations)≈2,线程并行度(Parallelism)=1
-
scrypt(Argon2id 不可用时)
- 参数 N=2¹⁷(约 128 MiB 内存),r=8,p=1
-
bcrypt(老系统兼容)
- 工作因子 ≥10,输入密码长度 ≤72 字节
-
PBKDF2(需要符合 FIPS-140 时)
- HMAC-SHA256 内部哈希,迭代次数 ≥600 000
五、细节说明
1. 盐(Salt)
- 每个用户都生成一个随机盐,和密码一起哈希。
- 防止黑客一次性用同一个计算结果去破解所有用户密码。
2. 椒(Pepper)
- 全局共用的一串秘密,不和数据库一起存放。
- 可以在哈希后再用 HMAC(带密钥的哈希)“二次加工”一次。
3. 工作因子升级
随着硬件越来越快,以前的参数可能不够“慢”了。常见做法是用户下一次登录时,用更高的参数重新哈希他们的密码。没登录的用户,其旧哈希暂时还留着。
六、为什么要选这些算法?
- 安全:它们设计时就考虑到要抗 GPU 暴力破解、抗侧信道攻击。
- 可调节:你可以随时在部署时、或者后期根据服务器性能调整“吃资源”程度。
- 社区认可:Argon2 是 2015 年国际比赛冠军,scrypt、bcrypt、PBKDF2 都有多年实战验证。
小结
- 永远用哈希,不要用可逆加密 来存用户密码。
- 加盐、设置合理的工作因子,必要时再加 椒。
- 优先选 Argon2id,再退而选 scrypt、bcrypt 或 PBKDF2。
- 定期 升级参数,保持防护强度。