密码长度与安全性 - 如何选择最佳密码长度
密码安全性的最大决定因素是"长度"。短密码可以被暴力破解 (brute force) 瞬间攻破,而每增加一个字符,组合数就会增加约 95 倍。本文以 NIST SP 800-63B 最新指南为核心,从熵的概念、哈希函数的计算成本、GPU 实测破解时间、密码短语与多因素认证的组合等多个角度,深入剖析密码长度与安全性的关系。
熵与密码强度的关系
定量评估密码强度的指标是"熵"(信息量)。熵以比特为单位表示,值越大,攻击者越难以猜测。计算公式如下:
熵 (比特) = log2(字符种类数字符数) = 字符数 × log2(字符种类数)
例如,使用英文大小写字母 + 数字 + 符号共 95 种字符时,每个字符贡献约 6.57 比特的熵。8 个字符约 52.6 比特,12 个字符约 78.8 比特,16 个字符约 105.1 比特。在安全领域,80 比特以上被认为"暂时安全",128 比特以上被认为"长期安全"。也就是说,使用 95 种字符集时,13 个字符以上可达到暂时安全水平,20 个字符以上可达到长期安全水平。
这里的关键在于,增加字符数比增加字符种类对熵的贡献更大。仅使用英文小写字母 (26 种) 的 16 个字符,熵约为 75.2 比特;而使用全部 95 种字符的 12 个字符,熵约为 78.8 比特,两者几乎相当。另一方面,即使仅使用英文小写字母,20 个字符的熵也能达到约 94 比特,超过 95 种字符 × 14 个字符 (约 92 比特)。"长度比复杂度更重要"这一说法的数学依据正在于此。
NIST SP 800-63B 指南要点
NIST (美国国家标准与技术研究院) 于 2017 年修订、2024 年发布第 4 版草案的 SP 800-63B,是国际上广泛参考的密码指南。信息安全入门书籍也有助于加深理解。该指南明确将"定期更换"和"强制复杂字符种类"列为不推荐做法,将长度定位为最重要的安全要素。
- 最低字符数:8 个字符以上 (服务提供商应设置的下限)
- 推荐字符数:15 个字符以上 (第 4 版草案正在考虑将最低要求提高到 15 个字符)
- 最大字符数:应至少允许 64 个字符
- 强制字符种类 (必须包含大写字母、符号等) 不推荐 - 用户容易陷入可预测的模式 (如在末尾添加 "!" 等),实际上对熵的提升贡献甚微
- 强制定期更换密码也不推荐 - 强制更换时,用户往往只做微小改动 (如递增末尾数字),无法真正提升安全性
- 强制与泄露密码列表进行比对 - 服务提供商应将用户设置的密码与已知泄露列表进行比对,匹配时应予以拒绝
NIST 重视"长度"而非"复杂度"的背景,除了前述熵的数学特性外,还有可用性研究的支持。研究证实,施加复杂规则会导致用户将密码写在便签上,或使用模式化的弱密码进行重复使用。
GPU 暴力破解时间实测数据
密码字符数越多,暴力破解所需时间呈指数级增长。下表基于英文大小写字母、数字和符号 (约 95 种),以最新 GPU (NVIDIA RTX 4090 级别,MD5 哈希每秒约 1640 亿次尝试) 为前提的估算破解时间。
| 字符数 | 组合数 | 熵 | 估算破解时间 (MD5) | 估算破解时间 (bcrypt) |
|---|---|---|---|---|
| 6 个字符 | 约 7350 亿 | 约 39.5 bit | 约 4.5 秒 | 约 23 万年 |
| 8 个字符 | 约 6.6 京 | 约 52.6 bit | 约 11 小时 | 约 20 亿年 |
| 10 个字符 | 约 6 × 1019 | 约 65.7 bit | 约 1.2 万年 | 事实上不可能 |
| 12 个字符 | 约 5.4 × 1023 | 约 78.8 bit | 约 1 亿年 | 事实上不可能 |
| 16 个字符 | 约 4.4 × 1031 | 约 105.1 bit | 约 8.5 × 1012 年 | 事实上不可能 |
使用 MD5 等高速哈希时,8 个字符约 11 小时即可被攻破;而使用 bcrypt (成本因子 12) 的服务,同样 8 个字符的破解时间约需 20 亿年。哈希算法的选择对密码的实际安全性影响巨大,这一点常被忽视。不过,由于服务器端的哈希算法不由用户选择,用户能做的最佳防护就是"设置足够长的密码"。
哈希函数的计算成本与字符数的关系
密码的安全性不仅取决于字符数,还很大程度上依赖于服务器端使用的哈希函数的计算成本。以下是主要哈希算法的特性比较:
| 算法 | GPU 尝试速度 (RTX 4090) | 特点 |
|---|---|---|
| MD5 | 约 1640 亿次/秒 | 速度过快,不适合密码存储。残留于遗留系统中 |
| SHA-256 | 约 220 亿次/秒 | 比 MD5 慢,但仍不足以用于密码存储 |
| bcrypt (cost=12) | 约 184 次/秒 | 故意降低速度。可通过成本因子调整计算量。输入限制 72 字节 |
| Argon2id | 数十至数百次/秒 | 2015 年密码哈希竞赛冠军。内存密集型设计,对 GPU 并行攻击有较强抵抗力 |
| scrypt | 数百至数千次/秒 | 内存密集型设计。Argon2 出现前的推荐算法 |
bcrypt 有将输入截断为 72 字节的规范,因此仅使用 ASCII 字符时实际上限为 72 个字符,UTF-8 编码的中文约为 24 个字符。这影响了部分服务的最大字符数限制。Argon2id 没有此限制,可以处理任意长度的密码。新服务的设计推荐采用 Argon2id。
需要注意的是,即使使用 bcrypt 或 Argon2id 等慢速哈希,短密码仍可能被字典攻击或基于规则的攻击所攻破。哈希的计算成本只是"争取时间",根本性的防御在于确保足够的字符数 (熵)。
为什么"长度"比"复杂度"更重要
许多服务要求"必须包含大写字母、小写字母、数字和符号",但 NIST 明确否定了这种做法。以下用具体数据说明原因。
"P@ssw0rd!" 是 9 个字符,包含了全部 4 种字符类型,但它是字典攻击排行榜上的典型弱密码。而 "mountain river cloud forest" 仅使用英文小写字母和空格 (27 种),共 30 个字符,熵高达约 142.5 比特,暴力破解事实上不可能。
复杂度规则适得其反的原因有三个。第一,用户会用可预测的模式来满足要求 (首字母大写,末尾添加 "1!" 等)。第二,复杂密码难以记忆,因此往往偏短。第三,无法记忆的密码更容易被以明文形式写在便签或文本文件中。
密码短语 vs 随机字符串
实现长密码有两种方法:"密码短语"和"随机字符串"。以下比较两者的特性:
| 比较项 | 密码短语 | 随机字符串 |
|---|---|---|
| 示例 | correct horse battery staple | kX9#mP2$vL7@nQ4 |
| 字符数 | 28 个字符 | 15 个字符 |
| 熵 | 约 77 bit (Diceware 6 个词) | 约 98.5 bit (95 种 × 15 个字符) |
| 易记性 | 高 (可通过故事记忆) | 低 (需要密码管理器) |
| 输入便捷性 | 高 (普通打字即可) | 低 (特殊符号输入繁琐) |
| 字典攻击抵抗力 | 取决于单词数量和词表大小 | 极高 |
密码短语的强度取决于"单词数量"和"词表大小"。使用 Diceware 方式 (7776 个词的词表) 选择 6 个词,熵约为 77.5 比特。如果仅使用日常常用词,容易被字典攻击攻破,因此随机组合不相关的单词至关重要。"我的猫很可爱"这样有意义的句子不适合作为密码短语,"椅子 紫色 潜水艇 辣椒 银河"这样不相关单词的组合才是理想的。
主密码 (用于解锁密码管理器) 适合使用密码短语,而各个服务的密码则最好使用密码管理器生成的随机字符串。
主要服务的密码字符数限制
不同服务的密码最小和最大字符数差异很大。最大字符数的限制通常源于前述哈希算法的规范或遗留系统的约束。
| 服务 | 最小字符数 | 最大字符数 | 备注 |
|---|---|---|---|
| 8 个字符 | 100 个字符 | 强烈推荐两步验证 | |
| Apple ID | 8 个字符 | 无限制 | 要求英文大小写 + 数字 |
| Microsoft | 8 个字符 | 256 个字符 | 正在推进无密码认证 |
| Amazon | 6 个字符 | 128 个字符 | 最低 6 个字符低于 NIST 标准 |
| X (原 Twitter) | 8 个字符 | 128 个字符 | 短信认证仅限付费用户 |
| 6 个字符 | 无限制 | 最低 6 个字符低于 NIST 标准 | |
| GitHub | 8 个字符 | 无限制 | 会与泄露密码列表进行比对 |
| 银行类 (一般) | 8 个字符 | 16-32 个字符 | 最大字符数偏短。多因遗留系统限制 |
值得注意的是,Amazon 和 Instagram 的最低 6 个字符低于 NIST 推荐的最低 8 个字符。此外,银行类服务 16-32 个字符的最大限制,多源于 bcrypt 的 72 字节限制或大型机时代的遗留系统,存在安全隐患。请在限制范围内尽可能设置较长的密码。
多因素认证的组合
无论密码多长,一旦通过钓鱼或键盘记录器被窃取就毫无用处。密码"长度"的防御与多因素认证 (MFA) 的防御针对不同的攻击向量,组合使用可以大幅提升防御能力。
- TOTP (基于时间的一次性密码):Google Authenticator 或 Authy 等应用生成的 6 位数代码。每 30 秒更新一次,即使被窃取也难以重复使用。但对实时中继的钓鱼攻击 (实时钓鱼) 存在脆弱性
- FIDO2 / WebAuthn (通行密钥):使用物理安全密钥或设备生物识别认证。抗钓鱼能力最强,NIST 也推荐此方式。Apple、Google、Microsoft 正以"通行密钥"的名义积极推广
- 短信认证:方便但存在 SIM 卡交换攻击和 SS7 协议漏洞导致的拦截风险。NIST 将短信认证定位为"受限"认证手段,建议尽可能迁移到 TOTP 或 FIDO2
理想的配置是"长密码 (或密码短语) + FIDO2 安全密钥"。这样可以同时对暴力破解、字典攻击、钓鱼和凭证填充攻击提供高度抵抗力。
密码管理器的最佳设置
密码管理器是现代密码管理中事实上的必备工具。密码管理相关书籍也可作为参考。但如果设置不当,反而可能增加风险。
- 主密码设置:用于解锁密码管理器的主密码,应使用 Diceware 方式设置 6 个词以上的密码短语。熵 77 比特以上为参考标准。主密码不应保存在任何地方,仅靠记忆管理
- 自动生成密码的长度:各服务的密码应自动生成 20 个字符以上的随机字符串。考虑到 bcrypt 的 72 字节限制,仅使用 ASCII 字符时 20-64 个字符是实用范围
- 剪贴板自动清除:启用复制的密码在一定时间后自动删除的设置。推荐 10-30 秒
- 与浏览器内置密码保存功能的区分:Chrome 和 Safari 的内置密码管理器也具备充分的加密功能,但如果需要跨平台使用或高级功能 (安全审计、共享保险库等),专用工具更为合适
泄露检查与密码策略设计指南
以下是面向个人用户和服务开发者的实践指南。
面向个人用户:
- 定期在 haveibeenpwned.com 检查自己的邮箱是否包含在过去的泄露中。该网站的 API 采用 k-匿名性模型,仅发送密码哈希值的前 5 个字符,密码本身不会被传输到外部
- 利用密码管理器的"安全审计"功能,一次性检测弱密码、重复使用和已泄露的密码
- 优先加强重要账户 (邮箱、金融、社交媒体) 的密码。邮箱账户因被用于其他服务的密码重置,应最优先保护
面向服务开发者:
- 密码最小字符数设为 8 个字符以上 (符合 NIST),推荐 12 个字符以上
- 最大字符数应允许 64 个字符以上。不必要的短上限会限制用户的安全性
- 不设置字符种类强制规则。取而代之,实现与泄露密码列表 (如 Have I Been Pwned 的 API) 的比对
- 哈希算法首选 Argon2id,次选 bcrypt (成本因子 12 以上)。绝对避免直接使用 MD5 或 SHA-256
- 实现密码强度计,为用户提供实时反馈。基于熵的评估 (如 zxcvbn 库) 更为理想
常见错误模式与对策
- 直接使用字典中的单词:"sunshine"、"football"、"dragon" 等常见英文单词会被字典攻击瞬间攻破。攻击者除了使用数百万词的字典外,还会全面尝试 l33t speak 转换 (a→@、e→3 等) 和键盘模式 (qwerty、1qaz2wsx 等)
- 在密码中包含个人信息:生日、宠物名字、地址的一部分等,可以从社交媒体的公开信息或数据泄露中轻易推测。攻击者日常使用收集目标公开信息来创建自定义字典的手法 (社会工程学)
- 在多个服务中重复使用同一密码:一个服务泄露后,使用相同密码的所有服务都会面临风险。这种被称为"凭证填充"的攻击,会自动将泄露的密码列表在其他服务上进行尝试,成功率约为 0.1%-2%。如果有 100 万条泄露记录,约有 1000-20000 个账户会被攻破
- 对密码进行微小改动后重复使用:"MyPassword1"、"MyPassword2"、"MyPassword3" 这样的模式,攻击者的基于规则的攻击可以轻易推测。从一个泄露的变体生成其他变体的工具已广泛流传
总结
密码的安全性取决于熵 (信息量),而最有效提高熵的手段是增加字符数。NIST SP 800-63B 建议最低 8 个字符、推荐 15 个字符以上,结合 bcrypt 或 Argon2id 等慢速哈希可确保实际安全性。个人用户应使用密码管理器生成 20 个字符以上的随机密码,主密码使用 Diceware 密码短语。再配合 FIDO2 / 通行密钥的多因素认证,即可实现当前最高水平的防御。想要确认密码字符数时,请使用字符计数器。