同意您的分析,允许符号允许更高的安全性,但通常不会那么多。尤其是与使用稍长的密码相比(假设密码是完全随机选择的符号)。使用 95 个可打印的 ascii 字符中的任何一个:
0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ!"#$%&\'()*+,-./:;<=>?@[\\]^_`{|} ~
(如果您将制表符或换行符等字符计为可打印字符,则更多)8 字符密码有 95^8 ~ 6.6 x 10^15 的可能性,而只有(区分大小写)字母和数字的 8 字符密码有 62^ 8 ~ 2.2 x 10^14 大约弱 30 倍。
但是,只有数字+小写+大写的 9 字符密码比允许特殊字符的 8 字符密码强两倍。因此,除非对密码的长度有硬性限制(实际上至少不需要对少于几百个字符的密码进行限制),即使使用有限的字符集,也很容易转向稍长的密码。
最大的潜在安全问题是他们是否认为允许密码中的特殊字符可能会导致其应用程序或数据库出现问题。\0
排除可能导致问题的不可打印的 ASCII 字符(例如,ASCII 控制字符 NUL ( )、退格 ( ) 等)是有正当理由的\b
,但设计良好的应用程序应该能够处理常规特殊字符,例如'
或-
不易受到注入攻击。应用程序应该能够处理这些类型的字符,例如它们出现在带有引号或连字符的名称中(例如,Conan O'Brien、Daniel Day-Lewis)。此外,由于不应将密码保存到数据库中或将密码返回给用户并立即进行散列处理,因此允许可打印的 ASCII 特殊字符无关紧要。
诚然,非 ASCII 特殊字符(如 unicode)存在一些可用性问题,出于可用性问题,禁止这些字符或以标准方式规范化它们可能是个好主意。散列函数通常需要一串字节,并且具有 ASCII 以外的特殊字符的密码可以在字节级别以不同的方式进行编码(例如,UTF-8、UTF-7、UTF-16、ISO-8859-1)。此外,除了不同的编码(您可以在应用程序级别保持一致)之外,您还必须担心外观相同的字母在 unicode 中具有不同的值。例如,下面的字符 Å 是unicode 00C5,但这个外观相同的字符是 Å unicode 212B而这个 Å 实际上是两个字符 - 一个带有unicode 030a组合字符的 ascii A,在 A 上添加了一个圆圈。
编辑:我刚刚注意到您将 £ 列为您的常见符号之一。不幸的是,这不是标准的 ASCII 符号。在 ISO-Latin-1 中,它是 byte A3
。在 UTF-8 中,它是两个字节C2 A3
。在 UTF-7 中,它是 ASCII 字符+AKM-
。在 UTF-16 中是00 A3
. 这些不同的编码意味着如果处理不当,您的哈希函数可能会在此字符上中断。当然,应用程序应该能够正确处理编码,但它可能会在某些设备子集上失败。此外,该字符可能在外国键盘上不可用。
某些应用程序/平台中的字符可能会出现可用性问题,'
或者"
在某些应用程序/平台中可能会被转换为智能引号‘’“”
(尽管这绝不应该在密码上下文中完成)。
最后,拥有唯一密码规则还有一个额外的理由——让用户更难拥有一个可以在任何地方重复使用的记住密码,这是一种可怕的安全做法。如果用户的“正常”密码不符合某个站点的唯一规则,那么当他们的正常密码在某个随机的其他站点(即以明文形式存储密码)上被盗用时,他们的帐户不会在具有唯一性的站点上被盗用规则。