术语表

salt(盐)是什么?对密码做哈希时添加的、每个用户各不相同的随机值

salt(盐)是对密码做哈希前添加的每个用户各不相同的随机值,即使密码相同保存值也不同,使彩虹表失效。从防御视角讲解为何需要它、与 pepper 的区别以及常见误解。

发布于 2026-06-27 更新于 2026-10-06 3 分钟阅读
本页目录

一谈到密码哈希,就必然会出现「salt(盐)」。在做哈希之前加上一个随机值,安全性就会大不相同。本文讲解其机制与要点(不会写出攻击步骤)。

为什么 salt 能让密码更安全

没有 salt 时,密码相同的人保存的哈希也相同。这给了攻击者两种手段:在预先计算好的对照表(彩虹表)里直接查出密码,以及把一个人的破解结果套用到所有密码相同的人身上。

加上 salt 后,即便同样是 "password123",每个用户的保存值也会完全不同。

无 salt:「password123」→ 所有人 哈希相同(用对照表立刻就能查出)
↓ 加上每个用户各自的 salt 后
A:salt_a + password123 → 哈希 X
B:salt_b + password123 → 哈希 Y(与 X 不同)
即便密码相同,只要 salt 不同,所有人的保存值就各不相同。预先计算的表因此失效。

出于同样的道理,salt 必须每个用户(最好是每个密码)都重新创建。如果所有人共用同一个 salt,相同密码的人之间保存值又会一致,大部分效果就丢失了。生成时要使用难以猜测的密码学随机数,创建好的 salt 要和哈希值一起保存(无需保密)。

另外,salt 守护的范围仅限于「预先计算好的表」和「针对重复使用密码的批量破解」。针对单个密码进行穷举的攻击,让它变慢并不是 salt 的工作,而是由 bcrypt/Argon2 这类故意做得很慢的哈希来承担。两者应对的威胁不同,所以必须搭配使用。

salt 的长度与生成方法

有两份文件确定了基准:

  • NIST SP 800-63B-4(美国的认证指南):salt 至少 32 位,并且选取方式要让保存的 salt 很少发生重复。每个密码都要同时保存 salt 和哈希
  • RFC 9106(Argon2 的规范):在密码哈希中推荐 16 字节(128 位),空间紧张时可减少到 64 位

生成时的三条规则:

  • 使用密码学随机数生成器。使用所用语言的安全随机函数,而不是 Math.random() 或 PHP 的 mt_rand() 这类可预测的函数
  • 不要用可猜测的值:用户名、邮箱地址、用户 ID 或注册时间都不能代替 salt
  • 修改密码时生成新的 salt。沿用旧的 salt,会在新旧哈希之间留下关联

实务上,标准的 bcrypt、Argon2、scrypt 实现会自动满足以上全部要求。如果你在写自己生成 salt 的代码,就把它当作需要复查的信号。

salt、pepper 与密钥拉伸的区别

密码保存涉及三种名称相似的措施。它们防御的对象不同,任何一种都不能替代另一种。

saltpepper密钥拉伸(慢速哈希)
是什么每个用户的随机值全体用户共用的秘密值故意让哈希计算变得代价高昂
是否保密否(与哈希一起保存)是(放在数据库之外)设置无需保密
防御对象预先计算的表、对相同密码的批量破解仅数据库泄露时的破解对每个哈希的穷举
实现方式bcrypt/Argon2 自动添加需要时自己添加bcrypt 的 cost、Argon2 的内存与迭代次数

NIST SP 800-63B-4 建议,把「只有验证方知道的秘密密钥」(通常称为 pepper)与密码哈希分开保存,最好放在 HSM 等专用硬件中。

真实案例:LinkedIn 未加 salt 的保存(2012 年)

2012 年 6 月,据报道约 650 万条据称属于 LinkedIn 用户的密码哈希被发布到网上。LinkedIn 确认其中一部分对应 LinkedIn 账户,并使受影响会员的密码失效。

该公司在官方博客中表示,它一直在从只对密码做哈希的系统,迁移到既做哈希又加 salt 的系统。当时,媒体引用的专家批评该公司只用 SHA-1 哈希来保护密码。

两点教训:

  • 没有加 salt 的哈希,可以通过预先计算好的表成批还原出常见密码
  • 即使正在迁移,只要还残留旧格式的哈希,泄露的影响就由那个旧格式决定

如何检查自己的环境

1

查看保存的字符串的形态

在你管理的开发数据库中,查看几条密码值。bcrypt 的话,$2b$12$ 之后的 22 个字符就是 salt。Argon2 的话,$argon2id$v=19$m=…,t=…,p=…$ 之后是以 $ 分隔的 salt 和哈希。如果值不符合任何一种形态,也没有单独的 salt 列,密码可能是在没有 salt 的情况下保存的。

2

用相同密码创建两个测试账户

在开发环境中,用相同的密码注册两个测试账户,比较保存的值。如果两者一致,说明 salt 没有起作用。同时确认修改密码时 salt 部分会改变。

3

查找手工拼装 salt 的代码

在代码中搜索 salt 一词,以及手工组合随机函数或哈希函数的地方。如果发现可预测的随机函数、复用用户名或 ID、或固定字符串,就换成所用语言或框架的标准密码函数。

4

迁移时参考实践指南

如何从没有 salt 的保存方式迁移(例如在登录时重新哈希),以及各算法的推荐设置,见密码的安全保存方法。

常见误解与正解

误解

  • salt 必须保密
  • 所有用户用共同的 salt 就行
  • 只要加上 salt,弱密码也安全

正解

  • salt 可以公开(和哈希一起保存)
  • 每个用户(最好是每个密码)用不同的随机数
  • salt 是针对「预先计算与重复使用密码破解」的对策。穷举对策由慢速哈希承担

本站的观点:先把 salt 和慢速哈希做对

pepper 是针对只有数据库被盗这种情况的附加措施。它增加了在别处管理秘密的工作,而一旦丢失这个秘密,就再也无法验证任何人的密码。

所以实务上,首要任务是用 bcrypt/Argon2 正确地使用salt+慢速哈希。等你已经有了密钥管理的体制,再考虑 pepper。

出处(一手资料)

  • NIST,“SP 800-63B-4 Digital Identity Guidelines: Authentication and Authenticator Management”(2025 年 8 月) — pages.nist.gov(salt 至少 32 位、保存 salt 和哈希、分开保存的秘密密钥)
  • RFC 9106,“Argon2 Memory-Hard Function for Password Hashing and Proof-of-Work Applications” — rfc-editor.org(密码哈希推荐 16 字节 salt)
  • OWASP,“Password Storage Cheat Sheet” — cheatsheetseries.owasp.org(加 salt、加 pepper、多数库会自动处理 salt)
  • PHC string format(Argon2 等使用的哈希字符串格式) — github.com/P-H-C
  • TechCrunch,“LinkedIn Confirms Hack And Leak Of 'Some' User Passwords”(2012 年 6 月 6 日) — techcrunch.com(约 650 万条、该公司关于迁移到哈希加 salt 的说明)
  • Computerworld,“LinkedIn provides breach update -- sort of”(2012 年 6 月 8 日) — computerworld.com(对只用 SHA-1 哈希的批评、密码失效)

接下来阅读

分类编号

CWE 对导致漏洞的弱点类型进行分类,MITRE ATT&CK 对攻击者的技术进行分类。两者均由 MITRE 维护,广泛用于标注漏洞信息和检测规则。

CWE™: Copyright © 2006–2026, The MITRE Corporation. CWE is a trademark of The MITRE Corporation. The MITRE Corporation hereby grants you a non-exclusive, royalty-free license to use CWE for research, development, and commercial purposes. Any copy you make for such purposes is authorized on the condition that you reproduce MITRE’s copyright designation and this license in any such copy. CWE Terms of Use

© 2026 The MITRE Corporation. This work is reproduced and distributed with the permission of The MITRE Corporation. MITRE ATT&CK and ATT&CK are registered trademarks of The MITRE Corporation. The MITRE Corporation (MITRE) hereby grants you a non-exclusive, royalty-free license to use ATT&CK® for research, development, and commercial purposes. Any copy you make for such purposes is authorized provided that you reproduce MITRE's copyright designation and this license in any such copy. ATT&CK Terms of Use

FAQ

Qsalt 必须保密吗?
A

不必。salt 不是『秘密的密钥』,可以和哈希值一起保存。它的目的不是保密,而是让相同密码的人保存值也各不相同,从而使预先计算(彩虹表)和针对重复使用密码的批量破解失效。需要保密的是另一种东西『pepper』(后述)。

Q所有用户能不能共用同一个 salt?
A

不行。salt 必须是每个用户(最好是每个密码)各不相同的随机值。如果用共同的 salt,相同密码的人之间保存值就会一致,攻击者只需一次穷举就能成批攻破多个账户。每次都要用密码学随机数重新生成。

Q需要自己实现 salt 吗?
A

通常不需要。bcrypt、Argon2、scrypt 这类专用哈希会自动完成 salt 的生成与保存(大多直接嵌在哈希字符串之中)。比起自己添加 salt,把它交给这些标准实现更安全、更可靠。

Q彩虹表是什么?
A

一种预先计算好的表,把常用密码与其哈希值对应起来。没有加 salt 保存的哈希,只要在这种表里查一下就能还原。加上 salt 后,建表时并不知道 salt 的值,所以预先计算好的表就失效了。

Qsalt 应该多长?
A

NIST SP 800-63B-4 要求至少 32 位。Argon2 的规范(RFC 9106)推荐在密码哈希中使用 16 字节(128 位)。标准的 bcrypt 和 Argon2 实现会自动生成长度足够的 salt,所以很少需要自己选择长度。

Q可以用用户名或用户 ID 当作 salt 吗?
A

不推荐。用户名和 ID 可以被猜到,相同的值(如 admin)在其他服务上也会出现,这就给针对这些值预先建表留下了余地。而且修改密码时 salt 也不会变。每次设置密码时,都要用密码学随机数生成器生成 salt。