最后更新:

密码长度与安全性 - 如何选择最佳密码长度

14 分钟阅读

密码安全性的最大决定因素是"长度"。短密码可以被暴力破解 (brute force) 瞬间攻破,而每增加一个字符,组合数就会增加约 95 倍。本文以 2025 年公开了第 4 版的 NIST SP 800-63B 为核心,从熵的概念、哈希函数的计算成本、暴力破解所需时间的量级、密码短语与多因素认证的组合等多个角度,深入剖析密码长度与安全性的关系。

熵与密码强度的关系

定量评估密码强度的指标是"熵"(信息量)。熵以比特为单位表示,值越大,攻击者越难以猜测。计算公式如下:

熵 (比特) = log2(字符种类数字符数) = 字符数 × log2(字符种类数)

例如,使用英文大小写字母 + 数字 + 符号共 95 种字符时,每个字符贡献约 6.57 比特的熵。8 个字符约 52.6 比特,12 个字符约 78.8 比特,16 个字符约 105.1 比特。

需要先说明一点:熵并不存在一条绝对的安全分界线。同样的比特数,面对每秒可尝试上千亿次的快速哈希,和面对刻意放慢速度的哈希,含义完全不同。熵只有与攻击者实际能达到的尝试速度相乘之后,才能换算成"大约需要多久才会被穷举"这一有意义的结论。因此更实用的理解方式是把熵当作一把相对刻度:比特数每增加 10,穷举所需的尝试次数就变为约 1024 倍。判断"够不够"时,应当同时看服务方使用的哈希算法、是否启用了多因素认证,以及该账户被攻破后的损失大小。

这里的关键在于,增加字符数比增加字符种类对熵的贡献更大。仅使用英文小写字母 (26 种) 的 16 个字符,熵约为 75.2 比特;而使用全部 95 种字符的 12 个字符,熵约为 78.8 比特,两者几乎相当。另一方面,即使仅使用英文小写字母,20 个字符的熵也能达到约 94 比特,超过 95 种字符 × 14 个字符 (约 92 比特)。"长度比复杂度更重要"这一说法的数学依据正在于此。

NIST SP 800-63B 指南要点

NIST SP 800-63B 的第 4 版于 2025 年 8 月公开,取代了此前的版本。围绕密码 (指南中称为"记忆式验证要素") 的字符数与策略,其要求可以整理如下。标注 SHALL 的项目为必须满足,标注 SHOULD 的项目为应当满足。

把 15 个字符与 8 个字符分成两档,是因为这两种情形下密码承担的责任不同。密码是唯一防线时,它必须独自抵挡穷举和撞库;而在多因素认证中,密码只需守住"知识"这一层,另一层由持有物或生物特征承担,因此对字符数的要求可以放宽。

第 4 版之所以从"不推荐"进一步走到禁止强制组成规则,理由在于这类规则实际上并没有扩大攻击者需要搜索的范围。当规则要求"必须含有大写字母和符号"时,绝大多数用户会选择成本最低的应对方式,也就是把首字母改成大写、在末尾追加一个固定符号。攻击者早已把这些变形写进了破解规则集,于是规则带来的只是记忆负担,搜索空间几乎没有增加。同样的道理也适用于按期强制更换:被迫更换时用户倾向于只递增末尾的数字,攻击者从一个泄露的旧密码就能推出新密码。

NIST 重视"长度"而非"复杂度"的背景,除了前述熵的数学特性外,还有可用性研究的支持。研究证实,施加复杂规则会导致用户将密码写在便签上,或使用模式化的弱密码进行重复使用。

暴力破解所需时间的量级

密码字符数越多,暴力破解所需时间呈指数级增长。下表是一个计算例:字符集取英文大小写字母、数字和符号 (约 95 种),并假定攻击者每秒可以尝试 1011 次。这里的每秒次数不是某台具体显卡的实测值,而是为了看清量级而设定的前提,实际速度会随算法、硬件规模和攻击方式而大幅变动。

字符数组合数熵穷举全部组合所需时间 (前提:每秒 1011 次)
6 个字符约 7350 亿约 39.4 bit约 7 秒
8 个字符约 6630 万亿 (6.63 × 1015)约 52.6 bit约 18 小时
10 个字符约 6.0 × 1019约 65.7 bit约 19 年
12 个字符约 5.4 × 1023约 78.8 bit约 1.7 × 105 年
16 个字符约 4.4 × 1031约 105.1 bit约 1.4 × 1013 年

阅读这张表时有两点必须注意。第一,它算的是穷举全部组合所需的时间,前提是密码为真正随机生成;如果密码源自单词、人名或键盘上的连续按键,攻击者根本不必逐个穷举,所需时间会缩短到与表中数值完全不同的量级。第二,前提中的每秒次数一旦改变,整张表就会同比例平移:把速度提高到 1000 倍,全部时间就缩短为千分之一。这也说明服务方选择的哈希算法会直接决定这张表的横轴:刻意放慢的哈希把每秒可尝试次数压低几个数量级,所需时间就随之延长同样的数量级。不过,由于服务器端的哈希算法不由用户选择,用户能做的最佳防护就是"设置足够长的密码"。

哈希函数的计算成本与字符数的关系

密码的安全性不仅取决于字符数,还很大程度上依赖于服务器端使用的哈希函数的计算成本。以下是主要哈希算法的特性比较:

算法在密码存储中的定位
MD5为求快而设计的通用哈希,速度过快,不适合用于密码存储。目前主要残留于遗留系统中
SHA-256比 MD5 更结实,但同样是以高速为目标的通用哈希,直接用于密码存储仍然不足
bcrypt (cost=12)专为密码存储设计,故意放慢速度,并可通过成本因子调整计算量。输入限制 72 字节
Argon2id2015 年密码哈希竞赛的获选算法。除计算量外还要求大量内存,因此对 GPU 的大规模并行攻击抵抗力更强。RFC 9106 将其列为首选
scrypt同样采用内存密集型设计,是 Argon2 出现之前的推荐算法。现有系统继续使用是合理的,新建系统则优先考虑 Argon2id

bcrypt 有将输入截断为 72 字节的规范,因此仅使用 ASCII 字符时实际上限为 72 个字符,UTF-8 编码的中文约为 24 个字符。这影响了部分服务的最大字符数限制。Argon2id 没有此限制,可以处理任意长度的密码。新服务的设计推荐采用 Argon2id。

需要注意的是,即使使用 bcrypt 或 Argon2id 等慢速哈希,短密码仍可能被字典攻击或基于规则的攻击所攻破。哈希的计算成本只是"争取时间",根本性的防御在于确保足够的字符数 (熵)。

为什么"长度"比"复杂度"更重要

许多服务要求"必须包含大写字母、小写字母、数字和符号",但 NIST 明确否定了这种做法。以下用具体数据说明原因。

"P@ssw0rd!" 是 9 个字符,包含了全部 4 种字符类型,却是字典攻击排行榜上的典型弱密码。原因在于它是把 "password" 按 a→@、o→0 这类固定替换改写而成的,而攻击者的规则集早已把这些替换全部收录,因此这些替换几乎没有扩大需要搜索的范围。换句话说,l33t 替换增加的是记忆和输入的麻烦,而不是强度。

与之相对,"mountain river cloud forest" 这种从一份 7776 个词的词表 (Diceware 使用的规模) 中随机抽出 4 个词的写法,熵约为 51.7 比特;抽 6 个词则约为 77.5 比特。它看上去只是几个普通的小写单词,强度却来自"随机抽取了几次"这一点,而不是字符种类的多少。关键在于单词必须由随机方式选出:如果是自己想出来的、彼此有关联的词,可选范围会远小于词表规模,熵也就无从谈起。

复杂度规则适得其反的原因有三个。第一,用户会用可预测的模式来满足要求 (首字母大写,末尾添加 "1!" 等)。第二,复杂密码难以记忆,因此往往偏短。第三,无法记忆的密码更容易被以明文形式写在便签或文本文件中。

密码短语 vs 随机字符串

实现长密码有两种方法:"密码短语"和"随机字符串"。以下比较两者的特性:

比较项密码短语随机字符串
示例correct horse battery staplekX9#mP2$vL7@nQ4
字符数28 个字符15 个字符
熵约 51.7 bit (7776 个词的词表中抽 4 个词)约 98.5 bit (95 种 × 15 个字符)
易记性高 (可通过故事记忆)低 (需要密码管理器)
输入便捷性高 (普通打字即可)低 (特殊符号输入繁琐)
字典攻击抵抗力取决于单词数量和词表大小极高

这张表里最值得注意的一行是熵。左侧的密码短语有 28 个字符,右侧的随机字符串只有 15 个字符,但熵却是右侧接近左侧的两倍。也就是说,用字符数来评估密码短语的强度,会大幅高估它的实际强度:密码短语的一个"单位"是一个单词而不是一个字符,因此字符数多并不等于抽取次数多。

密码短语的强度取决于"单词数量"和"词表大小"。使用 Diceware 方式 (7776 个词的词表) 时,4 个词约为 51.7 比特,6 个词约为 77.5 比特,每多抽一个词就增加约 12.9 比特。如果仅使用日常常用词,容易被字典攻击攻破,因此随机组合不相关的单词至关重要。"我的猫很可爱"这样有意义的句子不适合作为密码短语,"椅子 紫色 潜水艇 辣椒 银河"这样不相关单词的组合才是理想的。

主密码 (用于解锁密码管理器) 适合使用密码短语,而各个服务的密码则最好使用密码管理器生成的随机字符串。

如何面对服务方的字数上限

决定了自己想用多长的密码之后,下一个问题是服务方是否允许。麻烦的是,各家服务的最大字符数很少写在帮助页面里,写出来的也可能与实际实现不一致,而且会随着改版而变化。因此,与其去找一份"各服务上限一览",不如把它当作需要在自己的账户上确认的事项。

上限之所以存在,有两个常见的技术原因。一是哈希算法本身的规范,例如前面提到的 bcrypt 会把输入截断到 72 字节,超出部分不参与计算,于是服务方索性在输入阶段就设一个上限。二是数据库设计的历史遗留:在把密码或其派生值存进固定长度字段的年代,字段长度直接成了字符数上限,即使后来改用了现代的哈希,前端的校验规则也常常留在原处。反过来说,上限偏短本身并不一定意味着存储方式不安全,但它确实限制了用户能拿到的熵。

要做的事具体做法注意点
确认实际上限用密码管理器生成 32 个字符的密码尝试保存,被拒绝时依次降到 24 个、16 个字符有的服务不报错而是静默截断,保存后应立即退出并用完整密码重新登录以确认
记录确认结果把该服务实际接受的最长长度记在密码管理器的备注栏里改版后上限可能变化,下次更换密码时重新确认一遍
应对字符种类限制若符号被拒绝,就改用仅由大小写字母和数字构成、但更长的密码字符种类减少造成的熵损失,可以通过增加字符数补回来
上限偏短时在允许范围内取最长,同时为该账户启用多因素认证上限无法由用户改变,只能在其他层面补上防御
最小字数很宽松时不把服务要求的下限当作目标,长度由自己决定下限是面向全体用户的底线,不是推荐值
被强制要求字符种类先把密码加长,再补足所缺的字符种类用首字母大写、末尾加固定符号这类最小变形去应付,对搜索空间几乎没有贡献
被强制定期更换整体重新生成,而不是在原密码上做改动递增末尾数字的做法,会让攻击者从旧密码直接推出新密码
主密码它不受任何服务的上限约束,可以取到自己能记住的最长长度主密码只靠记忆管理,因此长度要与可记忆性取平衡

把这些整理成一条原则:在服务允许的范围内尽可能取长,上限短到无法取得足够熵的服务则必须靠多因素认证来补足;而在下限宽松的服务上,不要因为"8 个字符就能通过"而真的只设 8 个字符。字符数是少数几个完全由用户自己掌握的安全参数,把它交给服务方的校验规则来决定并不划算。想核对自己设定的长度时,可以用字符计数器确认。

多因素认证的组合

无论密码多长,一旦通过钓鱼或键盘记录器被窃取就毫无用处。密码"长度"的防御与多因素认证 (MFA) 的防御针对不同的攻击向量,组合使用可以大幅提升防御能力。

理想的配置是"长密码 (或密码短语) + FIDO2 安全密钥"。这样可以同时对暴力破解、字典攻击、钓鱼和凭证填充攻击提供高度抵抗力。

密码管理器的最佳设置

泄露检查与密码策略设计指南

以下是面向个人用户和服务开发者的实践指南。

面向个人用户:

面向服务开发者:

常见错误模式与对策

总结

密码的安全性取决于熵 (信息量),而最有效提高熵的手段是增加字符数。NIST SP 800-63B 第 4 版把最小字符数分成两档:密码是唯一验证手段时要求 15 个字符以上,作为多因素认证中的一个要素时要求 8 个字符以上;同时禁止强制组成规则和按期限强制更换。服务方再结合 bcrypt 或 Argon2id 等慢速哈希,就能把用户设定的字符数真正兑换成安全性。个人用户应使用密码管理器生成 20 个字符以上的随机密码,主密码使用 Diceware 密码短语。再配合 FIDO2 / 通行密钥的多因素认证,即可实现当前最高水平的防御。想要确认密码字符数时,请使用字符计数器。

分享这篇文章