← 返回题目列表

用户密码应该如何安全存储?

高频 中等 第 14 / 27 题 更新于 2026/07/28
密码存储加盐哈希bcrypt网络安全

简化版

绝对不能明文存密码,也不能只用 MD5/SHA 直接哈希(太快,容易被彩虹表和暴力破解攻破)。正确做法是:加盐(salt)+ 慢哈希算法是每个用户一个的随机值,和密码一起哈希,让相同密码的哈希也不同、彻底废掉彩虹表;慢哈希(bcrypt、scrypt、Argon2、PBKDF2)故意让计算变慢,大幅提高暴力破解的成本。核心:加盐防彩虹表,慢哈希防暴力破解。

详细版

为什么不能这样存

  • 明文:数据库一旦泄露,所有密码直接暴露,还可能被撞库到其他网站——最严重的错误;
  • 只 MD5/SHA 哈希:哈希不可逆看似安全,但:
    • 彩虹表:预先算好海量「常见密码 → 哈希」的对照表,一查就还原;
    • 暴力/字典破解:MD5/SHA 计算极快(每秒能算数十亿次),弱密码很快被爆破;
    • 相同密码哈希相同,一眼看出哪些用户用了同样的密码。

正确做法:加盐 + 慢哈希

存储:salt(随机)+ hash = 慢哈希(密码 + salt)
校验:用存的 salt,对用户输入的密码重新算慢哈希,和存的 hash 比对
  • 盐(salt):每个用户独立的随机值,和密码拼在一起再哈希。作用:相同密码因盐不同而哈希不同 → 彩虹表失效(攻击者没法预算,得为每个盐单独算);
  • 慢哈希算法bcrypt、scrypt、Argon2、PBKDF2——它们故意设计得(可调计算成本),让每次哈希耗时从「纳秒级」变成「几十毫秒」。对正常登录无感,但让暴力破解慢上亿倍、变得不可行。

完整版教学

一、密码存储的核心矛盾:既要能验证,又要不可逆

密码存储要同时满足两个看似矛盾的需求:

  • 要能验证:用户登录时,系统得判断「他输的密码对不对」;
  • 要不可逆:数据库万一泄露,攻击者不能从存储的内容反推出原始密码

哈希正好满足这个矛盾——它单向不可逆(存哈希,泄露也还原不了原文),但同一个密码每次算出的哈希相同(可用于验证:重新哈希用户输入,和存的比对)。所以密码存储的基础是「存哈希、不存明文」。

光哈希不够——普通哈希(MD5/SHA)有两个致命弱点,需要盐和慢哈希来补。

二、盐(salt):废掉彩虹表

彩虹表是攻击者预先算好的「常见密码 → 哈希值」超大对照表。如果你只是 SHA256(密码),攻击者拿到你泄露的哈希,一查彩虹表就还原出密码。而且相同密码哈希相同,一眼就能看出批量用户。

的作用就是打破「相同密码 → 相同哈希」

  • 给每个用户生成一个随机的盐,存储 hash = 哈希(密码 + salt),盐本身也存下来(盐不用保密);
  • 相同密码的两个用户,因为盐不同,哈希也完全不同 → 攻击者无法用一张彩虹表批量破解
  • 攻击者要破解,必须针对每个盐单独重算彩虹表——成本呈天文数字上升。

关键:盐必须每个用户随机且唯一(不能全站用同一个盐,那等于没加)。盐不需要保密,和哈希一起存即可,它的价值在于「随机性打破预计算」。

三、慢哈希:让暴力破解变得不可行

盐防住了彩虹表,但挡不住针对单个用户的暴力破解——攻击者拿到某用户的盐和哈希,把常见密码逐个 哈希(候选 + salt) 试。问题是 MD5/SHA 太快,每秒能试数十亿个,弱密码几秒就爆破。

慢哈希就是来解决「太快」的:

  • bcrypt、scrypt、Argon2、PBKDF2 故意让哈希计算很慢,且计算成本可调(work factor / 迭代次数);
  • 调到「正常登录耗时约几十毫秒」——对用户登录几乎无感,但攻击者每秒能试的次数从几十亿骤降到几千,暴力破解慢上百万倍以上,变得不划算;
  • 有的(scrypt、Argon2)还消耗大量内存,抵御 GPU/专用硬件的并行破解。

Argon2 是目前推荐的首选(密码哈希竞赛冠军),bcrypt 是久经考验的经典选择。别再用 MD5/SHA 直接存密码。

四、盐和慢哈希的分工

把两者的作用理清,就抓住了密码存储的精髓:

  • 对抗的是「预计算」攻击(彩虹表)——让攻击者无法提前算好对照表;
  • 慢哈希对抗的是「实时暴力」攻击——让攻击者算得慢、试不动。

两者缺一不可、配合使用。好在现代慢哈希算法(bcrypt/Argon2)内部已经自动处理了加盐——你调用它加密密码,它自己生成随机盐并把盐编码进输出结果里,校验时自动取出。所以实践中通常不用手动管盐,直接用 bcrypt/Argon2 库即可。

五、其他加固措施

  • 登录限流 + 锁定:限制单账号/IP 的登录尝试次数,防在线暴力破解;
  • 密码强度策略:要求足够长度和复杂度,避免弱密码(但别搞得太反人类);
  • 多因素认证(MFA):密码 + 短信/验证器,即使密码泄露也多一层;
  • 敏感操作二次验证泄露密码检测(对照已泄露密码库);
  • 传输加密:密码传输走 HTTPS,别在网络上明文传(详见 HTTPS 相关题目)。

六、常见误区

  • ❌ 明文存密码——最严重错误,泄露即全裸,还会被撞库。
  • ❌ 只用 MD5/SHA 哈希——太快 + 彩虹表,弱密码秒破,必须加盐 + 慢哈希。
  • ❌ 全站用同一个盐——等于没加盐,盐必须每用户随机唯一。
  • ❌ 以为哈希不可逆就绝对安全——不加盐挡不住彩虹表,不用慢哈希挡不住暴力破解。

六、常见误区与追问

考点正确口径
明文绝对不能存
普通哈希容易被彩虹表和高速撞库攻击
慢哈希加盐bcrypt、scrypt、Argon2 等专为密码存储设计
salt = random(16 bytes)
hash = Argon2id(password, salt, memoryCost, timeCost)
store: algorithm + params + salt + hash
verify by recomputing and constant-time compare

密码存储追求的不是“解密回来”,而是泄库后让攻击者很难批量猜出原密码。

  • 误区:密码加密后存库最好。 可逆加密意味着密钥泄露就能还原;密码应使用不可逆慢哈希。
  • 误区:MD5 加盐就足够。 MD5 太快,不适合密码存储;应使用 bcrypt、scrypt、Argon2。
  • 误区:所有用户共用一个盐也可以。 盐应每个用户随机生成,避免相同密码产生相同哈希。
  • 追问:盐和 pepper 区别是什么? 盐通常随哈希存库,pepper 是额外服务端秘密,放在配置或密钥系统中。
  • 追问:为什么慢哈希更安全? 它提高每次猜测成本,显著降低离线暴力破解吞吐。
  • 追问:忘记密码为什么不能找回原密码? 系统不应保存可还原密码,只能通过重置流程设置新密码。

七、加强记忆

密码存储绝不能明文、也不能只用 MD5/SHA 直接哈希(太快 + 彩虹表易破)。正确做法是加盐 + 慢哈希:盐是每用户随机唯一的值,打破「相同密码相同哈希」、废掉彩虹表(对抗预计算);慢哈希(bcrypt/scrypt/Argon2/PBKDF2)故意计算慢且成本可调,让暴力破解慢上百万倍(对抗实时爆破)。现代慢哈希已自动加盐,直接用即可,再配合登录限流、MFA、HTTPS 传输。