从各种字典单词中随机生成密码是否安全?

信息安全 密码 密码策略 密码破解 随机的
2021-09-03 03:02:07

我们都应该知道关于密码强度的 XKCD 漫画,它(适当地)暗示基于多个常用词的密码比诸如Aw3s0m3s4u(3或之类的密码更安全、更容易记住。

我有一个应用程序(多平台),我想为其生成一些安全的密码,而且我的密码要求要低得多:如果密码没有空格,我希望“多个符号、数字、混合 alpha 和 6+ 个字符” ,但如果密码有多个不连续的空格,我将放宽符号/数字/混合大小写限制,而是要求至少两个单词分别不少于 4 个字符,密码长度至少为 15 个字符。

问题不在于方面,而是关于生成:假设我想为用户生成一个易于记忆且难以猜测的密码,基于 5 个左右的字典单词生成密码在密码学上是否安全从 10k 单词列表中?(从字面上看,我的数据库中有 10k 个单词,从各种来源、电子邮件等中抓取。)它们都是非常常见的单词,长度不少于 3 个字符。

现在我不想制作这些一次性密码,但我怀疑我至少应该要求用户在使用这个生成的密码后登录时将其更改为其他密码,这很好,我可以,但我还希望用户可以选择(在更改密码时)生成符合我要求的“安全”密码。

从破解的角度来看,攻击使用此方案生成的密码有多容易/多难?没有固定长度,这个数据库表中的单词长度从3个字符到11个字符(environment例如数据库中的一个单词)?生成密码的程序不会选择 4 个或更少字符的两个单词(因此最短的密码可以是 1 个三字符单词、4 个五字符单词和 4 个空格,总共 27 个字符),它不会在密码中使用相同的术语两次。

根据我针对它运行的示例,程序生成的平均密码长度约为 34 个字符,这对我来说似乎可以接受。即使我们假设最少 27 个非空格字符(最后是 23 个字符)中的每一个都可以是 26 种可能的状态(a-z),那是23^262.54e+35可能性。

数据库中有 994 个词,长度为 3 到 4 个字符。

我们还可以假设攻击者拥有字典和生成参数/算法。这仍然安全吗,我可以从生成的密码中删除一个单词(仍然是 21 个字符,仅基于熵的18^26可能性(4.33e+32)),我看到的唯一问题是这不是基于字符熵,但是在单词熵上,这意味着 5 字密码是10000*9006*9005*9004*9003可能性,或6.5e+19可能性,而 4 字密码是10000*9006*9005*9004可能性,或7.30e+15. 与普通的 6 字符密码((26+26+10+33)^67.35e+11可能性:26小写字母、26大写字母、10数字、33符号)相比,它要强得多。

我做了另一个假设:用户写下来,他们总是这样做。怀疑一张纸上的五个随机单词(希望不是直接看到,但唉,这是最有可能的情况)不太可能被选为潜在的密码,而不是看起来像传统的复杂术语密码。

最后,在我回答实际问题之前,密码在存储到数据库之前经过加盐处理,然后用SHA-512算法进行 100 次散列,每个散列之间附加加盐。如果用户成功登录,则更改 salt 并创建新的密码哈希。(我认为这对暴力离线攻击没有多大帮助,但它应该有助于抵御我认为的主动在线攻击。)

DatabasePassword = SHA512(...SHA512(SHA512(SHA512(password + salt) + salt) + salt) + salt)...)

所以,最后,我的实际问题:

  1. 我的数学正确吗?(您不必一定要回答这个问题,我相信它在原则上足以证明我的担忧。)
  2. 一代是安全的还是我应该坚持使用“传统”密码生成?请注意,攻击者不知道用户的密码是使用此算法生成的还是由用户选择的,如果他们知道长度,攻击者可以做出假设,但这可能是安全的,也可能不是.
  3. 最后,我是否做出任何会显着改变(增加或减少)这个“想法”的安全性的假设?(例如,假设 6 个字符的密码的每个字符的熵是 95。)

为篇幅道歉,我习惯于过度解释自己以希望减轻困惑。


有人指出我的问题与这个问题非常相似,我想指出我的生成方法的差异(但老实说,它仍然足够相似,可以被认为是重复的,我把它留给社区决定):

  1. 每个单词都用空格分隔,这意味着除了第一个和最后三个字符之外的所有字符都具有额外的潜在状态。
  2. 密码不是由人选择的,它(大部分)是统一随机生成的。除了允许一个超短(3 或 4 个字符)单词之外,没有任何单词比其他单词更受欢迎,一旦随机生成器选择了该长度的单词,就不能再选择这些单词了。(虽然该单词在单词列表中的位置仍然是随机的,可能不会选择一个超短单词。)
  3. 这与单独的密码限制混合在一起,这意味着攻击者有两个向量可以尝试破解。用户可以选择满足“传统”要求的密码或满足“XKCD”要求的密码。
4个回答

首先,没有密码安全密码这样的概念。密码的目的是让攻击者难以猜到,猜到的难易程度取决于密码的使用方式:如果帐户在 3 次尝试失败后被锁定,则与攻击者相比,密码可能更弱可以尝试无限数量的密码,或者当攻击者可以访问散列密码时。

在您的情况下,您从一组 10k 个单词中随机选择 5 个单词来创建密码。假设攻击者知道您的字典(不太可能,因为您的要求很容易记住单词)以及从字典构造密码的方式,这意味着有 (10^4)^5 = 10^20 个变体。这类似于猜测 20 位数字或 12..13 个随机字母数字混合大小写字符的密码。对于大多数用途,此类密码通常被认为足够安全。

至于密码的存储:不要发明自己的方法,而是使用被证明是好的方法。有关详细信息,请参阅如何安全地散列密码? 在当前的形式中,我认为选择的方法很弱,因为您只使用了 100 次迭代和一个旨在快速的哈希函数。只是为了比较:PBKDF2已经建议在 2000 年至少进行 1000 次迭代,LastPass 在 2011 年使用 100.000 次迭代进行服务器端哈希。幸运的是,您可以通过使用更复杂的密码来弥补较弱的密码存储。

在我看来,您的计算是正确的。尽管如此,请考虑以下弱点:

  1. 攻击者可以并且将使用多个(很多)帐户注册您的服务。从那里,创建一个接近原始的单词列表是微不足道的。所以假设攻击者知道单词列表。
  2. 攻击者还将测试您的密码长度限制。如此处所述,12 个字符的最小密码长度对攻击者来说是一个很好的提示,即将使用连续的字典单词,从而减少搜索空间。
  3. 实际的单词列表也有所不同。考虑一个场景,你的单词列表包含超过 8 个字符的单词,而你的最大密码长度是 30。这意味着攻击者可以安全地假设不会用 4 个连续的 8 个字符的单词构造密码。与此类似,根据您选择的单词列表,可以存在许多假设。因此,我认为您错过的另一个考虑因素是字长熵。
  4. 最后,您为客户提供安全且易于记忆的密码生成器这一事实意味着他们使用它。因此,攻击者也可以安全地假设除了最具有安全意识的人之外的所有人都会使用您的单词列表和密码生成器。

尽管如此,我认为你提出的建议是安全的。即使考虑到上述所有因素,由此产生的搜索空间仍然很大。

这些都是我在您的描述中发现的可能会降低密码生成器安全性的所有问题/假设。供您考虑。

基于 MiaoHatola 的回答:

根据 MiaoHatola 的第一点,您的攻击者可以缩小列表并知道两个字典(一个是短词,另一个是 5 个字母词)。你说你的简短单词列表有 994 个条目。他们有 1/994 的机会在第一次尝试时得到简短的单词。现在,假设您使用 10,000 个常见的 5 个字母单词的列表。这些分数适用:

1/994 * 1/10000 * 1/9999 * 1/9998 * 1/9997

这个问题说明了第一次尝试猜测所有内容的综合机会,假设他们知道你的单词列表。

那是 9,934,037,100,000,000,000 分之一的机会只猜测单词,而不是单词的顺序。考虑到顺序,你会得到一个相当高的数字。我的计算器算不上那么高。

这个数字不包括 MiaoHatola 在第三点中提到的可能性,因为你说你没有最大长度。还有一件事:

与其每次只随机选择 5 个单词,为什么不随机选择这个数字呢?每隔一段时间多输入一个 7 个字母的单词。也许在末尾包含一个 2 位数字。尝试让攻击者猜测。这显着提高了您的安全性。在这一点上,你可以让散列密码无人看管,因为绝对数量的可能性是压倒性的。所以回答你的问题,是的。这增加了安全性。很多。

您不能将唯一性基于 27 个字符,因为这些字符不是随机的。

如果您有 10K 单词并使用 5 个单词,那么 10^20 个唯一密码(或短语)
100,000,000,000,000,000,000

这是否足以阻止蛮力攻击
以 100 毫秒为单位,即超过 30,000 年

但代价是用户输入 27 个字符。我不想输入 27 个字符。我可能会输入错误 1/2 的时间并且必须重新输入。随机顺序的5个单词不容易记住。

考虑来自 AZ、az、0-9 和 _ 的 6 个字符,
即 62,523,502,209 个唯一
作为用户,我宁愿记住并随机输入 6 个

我不认为写下 5 个随机单词是掩饰密码的好方法。特别是如果人们知道您的应用程序会这样做。