← 返回博客首页

密码强度分析与安全最佳实践:从熵值到通行密钥

密码安全的真正战场

讨论密码强度之前,先明确攻击模型——因为不同的攻击场景,决定完全不同的防御重点

攻击场景 攻击者能做什么 有效防御
撞库(credential stuffing) 拿其他站泄露的账号密码批量试 每站独立密码 + 泄露库筛查
在线爆破 直接对着你的登录接口试 限流 + 渐进延迟 + 锁定策略
离线爆破 已拿到数据库哈希,本地慢慢算 慢哈希(Argon2id / bcrypt)+ 强盐
钓鱼 诱骗你在假网站输入 通行密钥 / WebAuthn
SIM 劫持 接管你的手机号 不用短信做第二因素

大多数人以为自己在防「离线爆破」,实际被攻破的原因是撞库——也就是同一个密码在多个站复用。这也是为什么「每站独立随机密码」比「一个超强但通用的密码」重要得多。

判断一个密码到底有多强,可以先用 密码强度检测 量一下,再看下面的原理。

密码熵:公式与它的局限

理想公式

E = log₂(R^L),R 是字符集大小,L 是密码长度:

字符集 大小 8 位 12 位 16 位
纯数字 10 26.6 bit 39.9 bit 53.2 bit
小写字母 26 37.6 bit 56.4 bit 75.2 bit
大小写 + 数字 62 47.6 bit 71.4 bit 95.3 bit
全部可打印字符 95 52.6 bit 78.9 bit 105.2 bit

推荐基线:随机生成的密码 ≥ 12 位、熵值 > 70 bit。

公式失效的地方

这个公式假设每个字符独立均匀随机。人不是随机源,所以实际熵远低于名义值:

密码 名义熵(95 字符集) 实际可破解性
P@ssw0rd1 ~52 bit 字典 + 常见替换,几万次内命中
Qwerty123! ~52 bit 键盘序列 + 数字后缀,极快
Zhang1985! ~52 bit 常见姓氏 + 出生年,定向字典秒破
Tr0ub4dor&3 ~65 bit 仍是「单词 + 替换 + 后缀」结构

结论:长度比字符种类重要得多。 12 位纯随机小写字母(约 56 bit,实际也接近 56 bit)远强于 8 位四种类混合(名义 52.6 bit,实际可能不到 30 bit)。

zxcvbn:更接近现实的估算

现代强度检测(zxcvbn 及其衍生实现)不数字符集,而是先识别模式再估算猜测次数

  • 字典词(含常见人名、地名、品牌、影视角色)
  • 常见替换(a@o0i1
  • 键盘序列(qwerty1qaz2wsx
  • 重复与序列(aaaa12345
  • 日期(198520240101
  • 结构拆分(word + 123 + ! 分开算,再乘组合数)

这才是「为什么 correct-horse-battery-staple 强」的正确解释:四个随机常见词,组合空间是词表大小的四次方,而人脑只需记四个词。

破解速度:为什么哈希算法选型是生死线

同一份密码哈希,在不同算法下的离线爆破速度差几个数量级:

哈希算法 单张现代 GPU 每秒可试 8 位全字符集爆破耗时
MD5 ~10¹¹ 次 秒级
SHA-256 ~10¹⁰ 次 秒级
bcrypt(cost 12) ~10³ 次 数年
Argon2id(推荐参数) ~10² 次 数十年

关键结论:MD5/SHA 系列是快速哈希,设计目标是校验完整性,绝不能用来存密码——它们是给「追求速度」的场景用的,而密码存储恰恰需要「追求慢」。

存储侧的选型与参数细节见 密码哈希指南:bcrypt、argon2 与 scrypt 对比,需要实测哈希输出时可用 bcrypt 哈希工具;算法输出长度与安全性对照见 哈希算法速查表

NIST 已经推翻的三条老规矩

很多系统的密码策略还停留在 2003 年的 NIST 附录 A,而 SP 800-63B 已经明确反转

老规矩 现状 原因
每 90 天强制改密码 ❌ 不推荐 用户做可预测小改动,安全性反降
强制大小写 + 数字 + 符号 ❌ 不推荐 把用户推向 P@ssw0rd1 这类模式
密码提示问题 ❌ 应移除 答案多为公开信息
最小长度 ≥ 8 ✅ 保留(建议 ≥ 12) 长度是唯一稳定有效的复杂度来源
筛查已泄露密码 ✅ 强烈推荐 直接消灭撞库的主要弹药
允许粘贴密码 ✅ 推荐 否则会阻碍密码管理器

泄露密码筛查:k-匿名性怎么做到的

「检查用户密码是否在泄露库里」听起来要拿明文去比对,实际不需要——HIBP 的 Range API 用 k-匿名性 解决:

  1. 客户端计算密码的 SHA-1 哈希(注意:仅用于查询,不用于本地存储)
  2. 只把哈希的前 5 个字符发给服务端
  3. 服务端返回所有前缀匹配的哈希后缀(通常几百条)
  4. 客户端在本地比对完整哈希是否命中

服务端从头到尾没见过你的密码,也没见过完整哈希。目前该库收录量已达数亿级别。

MFA 与通行密钥:选型取舍

因素类型 抗钓鱼 抗 SIM 劫持 用户体验 建议
通行密钥 / WebAuthn ✅ 强 最好(生物识别一键) 首选
硬件安全密钥 ✅ 强 好(需携带) 高权限账号
TOTP 应用 ❌ 可被实时中转 中(需输 6 位) 通用次选
短信 SMS 仅兜底
邮箱验证码 取决于邮箱本身强度

通行密钥为什么天然抗钓鱼:凭据的私钥绑定在特定域名下,浏览器/系统只允许对匹配的域名签名。假网站即使在 UI 上伪装成真网站,也拿不到可用于真网站的签名——因为域名不匹配。这一点 TOTP 做不到:用户在假网站输入了 6 位码,攻击者可以立刻拿去真网站用。

服务端防护清单

密码安全不只是「让用户设强密码」,服务端这一侧的漏洞更常见:

存储

  • 永远不存明文,也不用可逆加密(密钥泄露等于全泄露)
  • Argon2id(首选)或 bcrypt(cost ≥ 12)+ 每用户独立随机盐(≥ 16 字节)
  • 不要用 MD5 / SHA-1 / SHA-256 裸哈希,也不要自己拼接 salt 后套 SHA
  • 保留算法标识,便于未来平滑升级(用户下次登录时重哈希)

登录接口

  • 限流按账号而非 IP(按 IP 会让 NAT 后的正常用户互相误伤)
  • 失败次数递增延迟,5 次后锁定 15 分钟比「永久锁定」好——后者本身就是拒绝服务漏洞
  • 登录失败提示不要区分「用户不存在」和「密码错误」(会泄露账号是否注册)
  • 重置令牌要一次性、短时效(≤ 30 分钟)、用后即焚,可用 令牌生成器 生成高熵值令牌

传输与日志

  • 全站 HTTPS,登录页 HTTP 直接 301
  • 日志中绝不记录密码、完整令牌、重置链接
  • 不要在 URL query 里传令牌(会进浏览器历史、Referer、代理日志)

监控

  • 检测异常登录(新设备、异地、短时间大量失败)
  • 接入泄露密码筛查,命中即强制改密

个人实践清单

  1. 每个重要站点用独立随机密码(靠密码管理器,不靠记忆)
  2. 主密码用 4–6 个随机词组成的口令,并开启 MFA
  3. 邮箱和主密码管理器优先开通行密钥——这两个失守,其他账号都能被重置
  4. 有通行密钥选项就开,别再选短信
  5. 定期用泄露检测查一遍自己的常用账号
  6. 不要因为「这个站不重要」就复用密码——撞库正是利用这一点
广告

常见问题

我按「大小写 + 数字 + 符号」设了 8 位密码,为什么强度仍然很低?

**因为字符集公式算的是「随机生成」的理想值,而你选的密码并不随机。** `E = log₂(R^L)` 在 95 字符集、8 位时给出约 52.6 bit,前提是**每个字符独立均匀随机**。但人手选的密码几乎必然落入模式:`P@ssw0rd1` 里的 `P@ssw0rd` 是字典词加固定替换,`1` 是常见后缀——攻击者不需要暴力 95^8 次,按字典+替换规则试几万次就命中。这也是为什么现代强度检测(如 zxcvbn)**不按字符集算**,而是识别字典词、键盘序列、重复、日期、常见替换,再估算「按这些模式需要试多少次」。结论:**长度比字符种类重要得多**。12 位纯随机小写字母(约 56 bit)远强于 8 位四种类混合(名义 52.6 bit,实际可能不到 30 bit)。

密码管理器安全吗?主密码一旦被破解是不是全丢了?

**是目前性价比最高的方案,风险远小于「所有网站复用同一个密码」。** 密码管理器的价值不只是「记住」,而是让每个站点都能用**独立随机长密码**——这直接消灭了撞库(一个站泄露连带攻破你所有账号)。关于主密码:**① 主密码必须是高熵长口令**(建议 4–6 个随机词,不是一句你喜欢的歌词);**② 必须开启 MFA**,这样即使主密码泄露,攻击者拿到云端保险库也登不进去;**③ 选支持现代 KDF 的产品**(Argon2id 或高 cost 的 PBKDF2/scrypt),它决定了离线爆破保险库文件的成本。用 [密码强度检测](/password-strength.html) 先量一下你的主密码熵值,再决定要不要换。

该不该强制用户每 90 天改一次密码?

**不该。** NIST SP 800-63B 已明确**反对**定期强制轮换,理由是有实证数据:被强制改密码的用户倾向于做**可预测的小改动**(`password1` → `password2` → `password3`),或者写在便签上,整体安全性反而下降。NIST 现在推荐的是**只在有证据时改**:检测到账号异常、密码出现在泄露库里、或发生安全事件时。另外两条同样已被推翻的老规矩:**① 强制大小写+符号的复杂度规则**——它把用户推向 `P@ssw0rd1` 这类可预测模式,应改为**只要求最小长度(建议 ≥ 12)并筛查泄露密码**;**② 密码提示问题**——答案往往是公开信息(母亲的姓氏、母校),应彻底移除。

短信验证码为什么不安全?该用什么替代?

**短信(SMS)验证码的主要威胁不是被截获内容,而是 SIM 卡劫持(SIM swap)**——攻击者凭伪造身份说服运营商把你的号码转到他的卡上,所有短信验证码就直接发到他手里了,且整个过程你往往毫无察觉。此外短信是明文传输、可能长时间停留在通知栏。替代方案按安全性排序:**① 通行密钥 / WebAuthn(FIDO2)**——基于公私钥,私钥不出设备,**天然抗钓鱼**(凭据与域名绑定,假网站拿不到签名),是目前最优解;**② 硬件安全密钥**(YubiKey 等)——同上,适合高权限账号;**③ TOTP 应用**(Authenticator)——比短信好得多,但仍可被实时钓鱼中转(攻击者把真网站代理给你);**④ 短信**——仅作为兜底,且不应作为唯一因素。给自己的账号做取舍时,优先给邮箱和主密码管理器开通行密钥,这两个一旦失守,其他账号都能被重置。

← 返回博客首页