顺序密码更新

信息安全 密码 密码管理 密码策略
2021-08-19 18:52:58

假设我有一个合理的 KDF,并且我让用户定期更改他们的密码并保留一些旧密码哈希以防止密码重用。

是什么阻止用户以某种可预测的顺序更改密码(当他们被要求时)?

hammurabi1
hammurabi2
hammurabi3

或者

winona2014Q3
winona2014Q4
winona2015Q1

或“基本”密码的其他一些明显排列?

显然,我不能存储密码的明文来检查序列,而且hammurabi3它本身是无害的。它可能是一种模式,也可能不是。

更改密码的好处是否无效,因为用户有机会将密码更改为几乎但不完全相同的密码?

我可以做些什么来改善这个缺陷(如果它是一个缺陷)?

进一步阅读

4个回答

除非您有人工管理员检查它们,否则您无法合理地阻止“序列密码”(这将有其自己的一组安全问题,甚至不考虑人工的昂贵性)。可以尝试自动检测此类模式,但您不能希望找到所有这些模式;此外,如果您只保留以前密码的哈希值,那么模式检测将必须是一个猜测和尝试的过程,这将是昂贵的。

此外,您的用户会发现模式检测系统不方便(因为它阻止了他们非常喜欢的序列密码),因此他们会与之抗争:他们会生气(当用户是客户时,这不是一个好主意),他们会要有创意,找到你没有想到的新序列。

更改密码的好处不会因序列密码而失效。更改密码的好处因定期更改密码毫无用处而无效(有关该主题的更多讨论,请参见此问题)。缺陷不在“序列密码”;政策要求定期更改密码是为了误解非常古老的传统,当用户使用计算机并尝试从网站购买东西时,这些传统是没有意义的,而不是挥舞步枪并试图将敌方士兵派往来世。这些策略是用户首先求助于序列密码的原因。

有几种不同的方法可以检查用户的旧密码和新密码是否相似,并且每种方法都有自己的优点和缺点。

字符串排列比较

第一种方法依赖于创建一个不允许的排列列表。这可能是正则表达式列表或您评估密码的一些类似定义的字符串更改。例如,您在密码中查找一个数字并将其递增,您查找月份名称并尝试下一个月的名称等。然后将更改后的新密码与旧密码进行比较以查看它们是否匹配。

如果您试图提出自己的禁止修改列表,这可能会很快变得复杂,因为您需要定义哪些转换会带来太大的安全风险的最低基线。如果您想了解一些想法,可以查看来自 UNC 研究人员的这篇论文的附录,其中列出了他们用来比较用户密码历史记录的转换。该论文也是确定正常环境​​中密码历史相似程度的重要资源。

算法比较

作为创建规则列表的替代方法,您可以评估两个密码的算法比较,例如 Levenshtein 距离或 Hamming 距离。这使您几乎可以说“我只是不希望密码比 X 更相似”,其中 X 是您决定的某个最小更改值。这可以很好地阻止那些从“Muffins10”到“Muffins11”但从“August14”到“November14”的人。

本文讨论了在改进密码破解规则的背景下评估密码的 Levenshtein 距离值,但它提供了有关如何进行此评估的不错的概述(和代码)。

字符掩码/拓扑比较

第三种选择是放弃专门查看字符,而是查看字符格式。您可以将字符转换为其各自的字符类型,创建掩码或拓扑。密码“Muffins10”将变为 ULLLLLLDD(其中 U = 大写,L = 小写,D = 数字,S = 符号)。然后,您可以阻止用户选择与之前密码完全相同或类似掩码的新密码。

这是一个非常激进的实施策略,因为它还会阻止您从“Muffins14”变为“Lovedog90”,即使它们似乎没有关联(除非您的狗被命名为 Muffins)。KoreLogic 一直致力于在其PathWell 拓扑项目中实现这一点,尽管这是防止在任何时候使用不太安全的密码掩码的更大努力的一部分。我相信他们的系统允许您防止在新密码和以前密码之间重复使用掩码。

这些方法中最大的挑战可能是与用户沟通他们的新密码选择被拒绝的原因。您是否给他们一个密码太相似的一般错误,或者您是否特别指出为什么新密码不可接受?

除非您指导他们解决问题,否则某些用户可能难以在这些系统下选择可接受的新密码。您可以提供有关如何创建更好密码的说明,但这将涉及改变很多人的习惯,并且可能会遇到阻力。

如何比较历史密码

好的,那么当您只有一个包含强哈希历史密码而不是明文的数据库时,如何进行这些比较?

在密码更改过程中,您可能已经提示用户输入他们现有的密码以及他们的新密码,这为您提供了以明文方式比较这两个密码的机会。这解决了即时评估问题,并且从长远来看,对于大多数用户而言,对于密码相似性可能足够有效。但是,您可能有一些用户发现他们可以在两个不同的密码变体之间轮换使用其他密码:Muffins10 --> 11Cupcakes --> Muffins12 --> 13Cupcakes

如果您真的担心这种威胁,那么不幸的是您没有太多选择。您可以使用字符串置换方法将新密码与每个规则一起转换,然后对其进行哈希处理,并在该用户的历史记录中查找哈希匹配项。其他两种方法都不兼容散列密码。编辑:实际上,我意识到如果您将历史掩码(理想情况下加密)存储在历史密码哈希旁边或代替它,字符掩码/拓扑方法仍然有效。

但是,如果您使用推荐的“昂贵”散列算法之一,那么运行您的规则并散列数百个结果将使用大量处理时间。用户会容忍 5 秒、10 秒或更长时间的延迟,然后才知道他们的密码是否被接受?这与规范有很大的不同,对于某些组织来说可能是不可接受的。

对此的替代方法不是散列密码历史记录,而是对其进行加密。您只能维护当前密码的哈希值,但在密码更改过程中,您会将过期密码存储为加密数据 blob。这将允许您在密码更改过程中解密历史密码并使用任何方法来查找密码相似性。

从理论上讲,使用加密存储以前的密码并没有太大的风险。既是因为加密在正确实施时确实工作得很好,而且因为旧密码不再有效,所以知道它不应该为攻击者提供太多优势。在您实施了防止当前密码和过去密码相似的措施后尤其如此。

我完全认识到有些人可能不认为这是一个可接受的替代方案,因为它会使密码历史的泄露风险稍大一些。然而,正如本文所解释的那样,我并不是唯一一个看到在这种情况下使用加密的好处的人

如果您存储以前的密码哈希,您可能会检查当前密码是否是您建议的变体。假设您的用户以前的密码是:

password = 5f4dcc3b5aa765d61d8327deb882cf99

如果您存储以前版本的密码哈希,您可以比较新密码的变体以确定它是否足够不同。因此,您将获取他们的新密码:password1并创建不同变体的哈希:

password = 5f4dcc3b5aa765d61d8327deb882cf99
password0 = 305e4f55ce823e111a46a9d500bcb86c
password2 = 6cb75f652a9b52798eb6cf2201057c73
etc.

如果其中任何一个与以前的哈希值之一匹配,您可以拒绝新密码。

我不确定为用户存储一堆旧密码哈希的安全含义是什么。我建议在实施这样的事情之前进行调查。

简短的回答:

没有什么可以阻止用户以某种可预测的顺序更改密码。

详细解答:

您可以尝试各种方法来检测顺序密码更改,但用户总是会发现您没有预见到的简单顺序模式。如果不是数字后缀 - 然后是数字前缀,如果不是数字 - 然后是字母。如果没有后缀和前缀 - 则将附加字符放在密码的顺序位置,如下所示:

xpassword
pxassword
paxssword
pasxsword
etc.

你根本无法预见每一个可能的想法。

提高密码安全性的更好想法是强制密码的长度合适。密码如:

twinkletwinklelittlestarhowiwonderwhatyouare

非常容易记住,对于可以打字的人来说很容易打字,而且比这样难以记住的密码更难破解:

aD@79]s^

看看这个著名的 xkcd 连环画- 它很有趣,但仍然真正指出了整个想法。