密码强度

<image>

密码强度，指一个密码对抗猜测或是暴力破解的有效程度。一般来说，指一个未授权的访问者得到正确密码的平均尝试次数。密码的强度和其长度、复杂度及不可预测度有关。强密码可以降低安全漏洞的整体风险，但并不能降低采取其他安全措施的需要。

使用强密码可以降低整体安全漏洞风险，但强密码并不能替代其他有效安全控制措施的必要性。特定强度密码的有效性在很大程度上取决于认证因素（知识因素、所有权因素、生物特征因素）的设计与实施。本文将重点探讨第一个认证因素。

攻击者提交猜测密码的速率是衡量一个系统安全性的重要因素。有的系统在多次尝试失败后会暂停登入一段时间，在没有其他安全缺陷时，这种系统可以用相对简单的密码保护。然而，系统以某种形式存储用户密码信息，一旦这些信息因系统安全被攻破等原因泄露，用户密码就可能面临风险。

2019 年，英国国家网络安全中心（NCSC）分析了泄露账户的公共数据库，以统计人们常用的单词、短语和字符串。榜单中最流行的密码是 "123456"，出现次数超过 2300 万次。排名第二的字符串 "123456789" 的破解难度并没有显著提升，而前五名中还包括 "qwerty"、"password" 和 "1111111"。

## 创建密码

密码可以被自动（使用随机方式）或人为创建出来，后一种更为常见。暴力破解随机密码的强度可以精确计算，而计算人类产生的密码强度是比较难的。

通常，当人们为计算机系统或互联网网站创建新账户时，系统会要求其选择密码（有时会提供建议或设置规则限制）。由于人类在这类任务中往往遵循特定模式，而这些模式通常会被攻击者利用，因此只能对密码强度进行粗略估计。此外，密码猜测程序可广泛获取常用密码列表，其中包括各种人类语言的大量在线词典、从各类网络商业和社交账户泄露的明文及哈希密码数据库，以及其他常见密码。这些列表中的所有条目均被视为弱密码，其简单变体也不例外。

当下，虽然有便于使用的随机密码生成程序，但这些程序生成的随机密码往往让人难以记住，所以人们还是更倾向于自己设置密码。不过，这种做法本身就存在安全隐患。因为一个人的生活方式、娱乐喜好以及其他突出的个人特点，通常会对其密码的选择产生影响。而且，如今网络社交媒体十分盛行，获取他人信息变得轻而易举。

## 密码验证

使用密码进行身份验证的系统必须具备某种方式来检查为获取访问权限而输入的任何密码。如果有效密码只是简单地存储在系统文件或数据库中，那么获得系统足够访问权限的攻击者将获取所有用户密码，这会让攻击者得以访问被攻击系统上的所有账户，而且用户若在其他系统使用了相同或相似的密码，这些系统也可能面临风险。降低这种风险的一种方法是，不存储密码本身，而是仅存储每个密码的加密哈希值。像安全哈希算法（SHA）系列这样的标准加密哈希算法极难逆向破解，所以获取到哈希值的攻击者无法直接还原出密码。然而，攻击者一旦掌握了哈希值，就能在离线状态下快速测试其猜测的密码。市面上有很多密码破解程序，这些程序可以针对窃取到的加密哈希值测试大量的尝试密码。

计算技术的进步不断提升密码猜测测试速度。例如，2010 年佐治亚理工学院研发出利用通用图形处理器（GPGPU）大幅加速密码破解的方法。Elcomsoft 公司于 2007 年 8 月发明了使用普通显卡实现更快密码恢复的技术，并迅速在美国申请了相关专利。截至 2011 年，市售产品宣称使用当时的高端图形处理器，可在标准台式机上实现每秒测试 11.2 万个密码的速度。此类设备能在一天内破解六位单字母密码。通过将计算任务分配至多台配备类似 GPU 的计算机，破解速度可按设备数量同比提升。目前存在需要较长计算时间的特殊密钥拉伸哈希算法，可降低密码猜测速率。尽管使用密钥拉伸被视为最佳实践，但许多通用系统仍未采用这一技术。

另一种可能进行快速猜测的情况是当密码被用来生成加密密钥时。在此类场景下，攻击者可快速验证猜测的密码是否能成功解密加密数据。例如，某商业产品宣称每秒可测试 10.3 万个 WPA 预共享密钥（PSK）密码。

如果密码系统仅存储密码的哈希值，攻击者可以预计算常见密码变体及所有短于特定长度的密码的哈希值，从而在获取哈希值后实现密码的快速恢复。利用彩虹表技术可以高效存储大量预计算的密码哈希值。若要挫败此类攻击，可在存储哈希值的同时附加一个称为 "加密盐值" 的随机数。盐值会在计算哈希时与密码混合，这意味着攻击者在预计算彩虹表时必须为每个密码存储所有可能盐值对应的哈希结果。如果盐值的取值范围足够大（例如 32 位数字），这种攻击方式将变得不可行。然而许多常用认证系统并未采用盐值机制，互联网上甚至存在针对此类系统的彩虹表库。

### 熵作为衡量密码强度的指标

密码强度由信息熵（单位为香农，Sh）决定，这一概念源自信息论。它可被视为存储特定类型密码所需的最小信息量。相关指标是确定猜出密码所需猜测次数的以 2 为底的对数值，通常称为 "熵值位数"。例如，一个具有 42 位熵值的密码，其强度等同于通过公平抛硬币随机生成的 42 位字符串。换句话说，破解 42 位熵值的密码需要进行 2⁴² 次（4,398,046,511,104 次）尝试才能穷尽所有可能。因此，密码的熵值每增加 1 位，所需猜测次数就翻倍，使攻击者的破解难度提升一倍。平均而言，攻击者需要尝试半数可能的密码组合才能找到正确答案。

### 随机密码

随机密码是由指定长度的符号串构成，这些符号通过随机选取过程从某个符号集中产生，且每个符号被选中的概率均等。符号可以是字符集（如 ASCII 字符集）中的单个字符、设计成可发音的音节，甚至是单词列表中的单词（从而形成密码短语）。

随机密码的强度取决于底层数字生成器的实际熵值；然而这些生成器往往并非真正随机，而是伪随机的。许多公开可用的密码生成程序采用编程库中的随机数生成器，这类生成器仅提供有限的熵值。但大多数现代操作系统都配备了适用于密码生成的加密安全随机数生成器。此外，还可使用普通骰子生成随机密码（详见随机密码生成器 § 增强方法）。随机密码程序通常能够确保生成的密码符合本地密码策略，例如通过始终混合生成字母、数字和特殊字符。

对于通过随机选择过程生成的密码（从包含 N 个可能符号的集合中选取长度为 L 的符号串），其可能的密码数量等于字符集大小的 L 次方（即NL）。增加密码长度 L 或字符集大小 N 均可增强生成密码的强度。在假设密码中每个符号独立生成的前提下，通过信息熵衡量的随机密码强度，等于可能密码数量的以 2 为底的对数（即 log₂(NL)）。因此，随机密码的信息熵 H 可由以下公式表示：$H = \log_2 N^L = L\log_2 N = L {\log N \over \log 2}$其中，N 为可能的符号数量，L 为密码中的符号位数。H 的单位为比特。在最后一个表达式中，对数的底数可以是任意值，但需保持底数一致。

符号集｜符号数量 N｜每个符号的熵值 H

阿拉伯数字（0–9）（例如 PIN 码）｜10｜bits

十六进制数字（0–9，A–F）（例如 WEP 密钥）｜16｜4.000 bits

不区分大小写的拉丁字母（a–z 或者 A–Z）｜26｜bits

不区分大小写的字母数字组合（a–z 或者 A–Z，0–9）｜36｜bits

区分大小写的拉丁字母（a–z，A–Z）｜52｜bits

区分大小写的字母数字组合（a–z，A–Z，0–9）｜62｜bits

除空格外的所有 ASCII 可打印字符｜94｜bits

所有拉丁字母补充-1字符｜94｜bits

所有 ASCII 可打印字符｜95｜bits

所有扩展 ASCII 可打印字符｜218｜bits

二进制（0–255 或 8 位 或 1 字节）｜256｜8 bits

Diceware 单词列表｜7776｜每个单词 bits

## 弱密码

弱密码是易于猜测的密码，主要有以下几种：

- 顺序或重复的字符：“12345678”、“111111”、“abcdefg”、“asdf”、“qwer”键盘上的相邻字母。
- 使用数字或符号的仅外观类似替换，例如使用数字“1”、“0”替换英文字母“i”、“O”，字符“@”替换字母“a”等。
- 登录名的一部分：密码为登录名的一部分或完全和登录名相同。
- 常用的单词：如自己和熟人的名字及其缩写，常用的单词及其缩写、宠物的名字等。
- 常用数字：比如自己或熟人的生日、证件编号等，以及这些数字与名字、称号等字母的简单组合。

下面是一些常见的弱密码：

- admin —— 太容易猜出
- 123 —— 同上
- abcde —— 同上
- abc123 —— 同上
- 123456 —— 由于文化因素极其常用
- 1234 —— 同上
- 888888 —— 同上
- 1234567890 —— 同上
- susan —— 常见人名
- DonaldJTrump —— 高知名度人物
- monkey —— 常见动物名且正好六位
- password —— 经常被使用，极易猜出
- p@$$\/\/0rd —— 简单的字母替换，易被软件破译
- rover —— 宠物的常用名称，也是一个单词
- 12/3/75 —— 日期
- nbusr123 —— 可能是用户名，如果是这样的话很容易被猜出
- asdf —— 常用键盘的键排列
- qwerty —— 常用键盘的键排列
- aaaaa —— 重复的字母，极易被破解
- administrator ——太容易猜出

以上仅列举了极少部分弱密码。

一家美国公司SplashData曾经总结出2011年最弱的25个密码，部分已列于上方。而像let me in这样的密码由于属于常见词组，很容易被破译。据统计，3.8%的密码是字典里的单词，12%的密码是单词加一个数字，其中2/3的机会密码是数字1。

很多用户不更换预设密码，而大部分计算机系统的预设密码可以在网络上找到，极易被破解。如果用户使用个人资讯（例如学号、朋友的名字、熟人的生日、电话号码或驾驶执照号码等）作为密码，那么密码便会很容易被破解，因为如今很多个人资讯都可以在网络上找到。

太短的密码，虽然容易输入，但是也很容易被攻破。

## 强密码

一个强密码通常长度足够长，排列随机，这样就需要花很多时间才能够破解。下面是强密码的一些例子（由于以下实例已经公开，所以已经不具备安全性，只作为说明例子）：

- t3MEIfreryeT45410A ——不是字典的单词，既有数字也有字母
- w2M1gD1cxJhs5UH4pQh1EgjOU9yWYRkk ——同上
- Convert_100£ to Euros! ——足够长，并且有扩展符号增加强度
- ot$fet÷×’Fr54⅛9&%u ——含键盘上没有的字符
- 9fad37a6aab5912dfa273521d11e0175fa0e8c95 ——随机字串
- aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbccdeertttteferwrwerewrwererewreew ——很长的字串几乎不可能在短时间之内被破解
- hellomicrosoftwikiwikipediaandadminadmintestactioneditsection ——同上
- RBDeT9hqRfS9gw9bEXmRhBrkkgCs2NMfpzWfQXfN3MPZW25wSsHWEsbexVpYtsWs ——同上
- ru0 ej03m06vm03rm3vu04u3d9 g3fu/32u03h3w.6qul4 ——同上，对于两者之间使用不同输入法的人极难以破解
- correcthorsebatterystaple——够长且无意义的句子或单词组合

上面列出的强密码的例子的共同特点是相对较长，使用大小写字母、数字和符号的组合。密码越长，使用的符号种类越多，就越难破解。值得注意的是，有些系统不支援例如：“#”、“@”和“!”等等符号作为密码中的字符，因为这些字元可能在有些键盘很难找到。在这种情况下，增加其它的数字或字母可以达到同样的安全效果。

一个10位长的随机密码，比如“BpR#e!ai@$”，虽然强度远弱于上面列出的密码，但由于常用键一共为95个，因此有$95^{10}$种组合，是不可能在短时间内通过全部列举来破译的。

目前的密码建议为：即使没有使用大小写字母或加入其他符号，只要密码够长，使用一些无意义但便于记忆的句子或单词组合也足够安全。例如上例的“correcthorsebatterystaple”就是由四个英文单词组成。

### 国家标准技术研究所改正建议

2017年6月，国家标准技术研究所（NIST）发布新的《800-63》指引第三版，改正已沿用超过十年、受各大政府机构、银行、业界采用的旧建议，不再强调使用人脑难以记忆的特别符号、数字的无意义组合，而且亦不再建议密码需每九十日汰换，因为经研究证明此项指引并没有对系统安全带来有益的效果。NIST文件的旧版原作者伯尔（Bill Burr）并在《华尔街日报》访问中公开道歉，称当时他并无得到可靠的数据作严谨研究，只依靠来自八十年代、不合时宜的旧文件作为参考，而他的建议亦没有考虑到一般人的生活习惯及思考模式。负责撰写新版指引的NIST顾问格拉西（Paul Grassi）指出，旧的要求不利使用，对抵挡骇客攻击的作用不大；如果用户能够在脑海中构想出一幅其他人无法想像的图画，以此作为密码便是最好的，一句够长的完整句子，会优于较短的字母、数字及符号混合密码。华尔街日报引用广泛流传的xkcd漫画，指出只要密码够长，拼合几个看似无意义、但便于该用户记忆的字词作为密码，更能有效抵挡骇客攻击，暴力破解会需要更久的时间。

## 保护用户密码

通常，计算机用户被建议“不要在任何地方因任何原因写下密码”或“不要在不同的帐号使用同一个密码”。实际上，一个计算机用户通常有十几个受密码保护的帐号，并使用同一个密码。而那些试图使用不同密码的用户往往由于密码太多，而记不清哪个帐户和哪个密码相对应。2005年的一次安全会议上，来自微软的一个专家提出：“我认为密码策略应改为你可以写下你的密码。我有68个不同的密码，如果我不允许将他们写下来，我将怎么办？我不得不使用同样的密码”。比较好且实际的建议是在一个低安全性的帐号（如bbs）使用简单的密码，在高安全性的程序（例如：网络银行）使用强密码。

一旦密码被写下来，用户不能将它放在一些明显的地方，如通信录，抽屉等。最糟糕可能也是最常见的情况是密码被写在一张便条纸上，放在计算机附近。比较安全的做法是放在保险箱里。

亦可使用密码管理器管理密码。