密码应该使用什么哈希算法存储?
用户密码不能明文保存,也不应该使用 AES 等可逆算法直接加密后保存。正确做法是使用专用密码哈希算法,让服务器能够验证密码,却无法从数据库中还原原始密码。
结论先说:
新系统优先使用 Argon2id。无法使用时选择 scrypt;遗留系统可继续验证 bcrypt,并在用户登录成功后逐步迁移;必须满足 FIPS-140 时可使用 PBKDF2-HMAC-SHA-256。
密码为什么不能直接加密
加密是可逆的。系统要验证或恢复明文,就必须持有解密密钥。攻击者一旦同时拿到数据库和密钥,所有密码都会直接暴露。
密码认证并不需要恢复明文,只需要回答一个问题:用户这次输入的密码,是否和注册时相同?
因此,密码应使用单向哈希保存。

注册时,服务端计算密码哈希并保存结果;登录时,根据记录中的算法和参数重新计算,再使用安全比较函数判断是否一致。
为什么 SHA-256 也不能直接存密码
MD5 和 SHA-1 已经不适合作为现代密码存储方案,但把它们换成单次 SHA-256 仍然不够。
SHA-256 的问题不是“已经被破解”,而是计算速度太快。它原本用于数据摘要、完整性校验和数字签名,快速计算是优点;密码数据库泄漏后,这个优点却会帮助攻击者使用 GPU 高速尝试候选密码。
密码哈希需要具备三个能力:
慢:每次猜测都要消耗明显的计算时间。
可调成本:硬件变快后,可以提高迭代次数或内存占用。
内存困难:增加 GPU、ASIC 大规模并行破解的成本。
密码哈希并不是让攻击者“无法计算”,而是让其每猜一次都付出更高代价。
当前应该选择什么算法

参考参数
OWASP 当前给出的最低参考配置为:
Argon2id:内存至少 19 MiB、迭代次数 2、并行度 1。
scrypt:
N = 2^17、r = 8、p = 1。bcrypt:cost 至少 10,并注意 72 字节输入限制。
PBKDF2-HMAC-SHA-256:至少 600,000 次迭代。
这些数字是参考基线,不是永远不变的固定答案。生产环境应进行基准测试,在不明显影响登录体验和系统稳定性的前提下,选择尽可能高的成本参数,并定期复查。
Salt、成本参数和 Pepper
一个合格的密码存储方案不仅包含算法名称,还包含 Salt 和成本参数。

Salt
Salt 是每个密码独立生成的随机值。它的作用是:
让两个相同密码产生不同哈希结果;
阻止攻击者使用预先计算的彩虹表;
避免一次计算同时匹配数据库中的大量用户。
Salt 不需要保密,可以和哈希结果一起存储。现代密码哈希库通常会自动生成和管理 Salt,不建议自行拼接字符串实现。
成本参数
Argon2id 的内存、迭代次数和并行度,bcrypt 的 cost,以及 PBKDF2 的迭代次数,都属于成本参数。
成本越高,正常登录和攻击者猜测密码都会变慢。参数过低没有足够防护,参数过高则可能拖慢服务,甚至放大拒绝服务风险,因此必须通过实际压测确定。
Pepper
Pepper 是可选的全局秘密值,用于增加纵深防御。它与 Salt 的区别是:
Salt 每个用户不同,可以公开;
Pepper 通常由系统共享,必须保密;
Pepper 不应存放在密码数据库中,应放在密钥管理系统、HSM 或受保护的执行环境中。
Pepper 不能代替 Salt,也不能弥补弱算法和弱密码。
数据库里实际保存什么
Argon2id 的完整记录通常类似:
$argon2id$v=19$m=65536,t=3,p=1$Salt$Hash
其中包含:
算法和版本;
内存、迭代次数、并行度;
Salt;
最终哈希值。
这些信息可以公开保存,因为安全性不能依赖隐藏算法和参数。需要保密的是用户原始密码,以及可选的 Pepper 或服务器密钥。
数据库字段应预留足够长度。与其把 Salt、参数和哈希拆成多个字段,更常见的做法是直接保存密码库生成的完整编码字符串。
旧系统怎么迁移
不要尝试“解密”旧哈希,因为哈希本身不可逆。推荐采用登录时升级:
保留旧算法的验证能力;
用户使用原密码成功登录;
检查当前算法或成本参数是否过时;
使用 Argon2id 重新计算;
用新记录替换旧哈希。
长期未登录的用户可以继续保留旧记录,或在风险较高时要求重置密码。
常见错误
明文保存密码;
使用 AES 加密密码,并把密钥放在同一套系统中;
使用 MD5、SHA-1 或单次 SHA-256;
所有用户共用同一个 Salt;
自己设计“多轮哈希”或自创密码算法;
把 Pepper 和密码表存放在同一数据库;
忽略 bcrypt 的 72 字节限制;
多年不调整成本参数;
在日志、异常信息或监控系统中输出密码;
在客户端先哈希,然后把哈希值当成可直接登录的密码。
客户端哈希不能替代 HTTPS 和服务端密码哈希。如果客户端哈希值可以直接用于登录,它本身就成了新的密码,攻击者拿到后仍然可以重放。
最后的选择
普通业务系统可以直接遵循这套规则:
新系统:Argon2id;
不支持 Argon2id:scrypt;
已使用 bcrypt:继续验证,并逐步迁移;
需要 FIPS-140:PBKDF2-HMAC-SHA-256;
MD5、SHA-1、单次 SHA-256:尽快淘汰。
密码哈希主要降低数据库泄漏后的离线破解风险。完整的认证系统还需要 HTTPS、登录限流、泄漏密码拦截、多因素认证、日志脱敏和安全的密码重置流程。
参考资料
OWASP Password Storage Cheat Sheet
https://cheatsheetseries.owasp.org/cheatsheets/Password_Storage_Cheat_Sheet.htmlRFC 9106:Argon2 Memory-Hard Function
https://www.rfc-editor.org/rfc/rfc9106.htmlNIST SP 800-63B:Authentication and Lifecycle Management
https://pages.nist.gov/800-63-4/sp800-63b.html
评论