有几种不同的方法可以检查用户的旧密码和新密码是否相似,并且每种方法都有自己的优点和缺点。
字符串排列比较
第一种方法依赖于创建一个不允许的排列列表。这可能是正则表达式列表或您评估密码的一些类似定义的字符串更改。例如,您在密码中查找一个数字并将其递增,您查找月份名称并尝试下一个月的名称等。然后将更改后的新密码与旧密码进行比较以查看它们是否匹配。
如果您试图提出自己的禁止修改列表,这可能会很快变得复杂,因为您需要定义哪些转换会带来太大的安全风险的最低基线。如果您想了解一些想法,可以查看来自 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。这将允许您在密码更改过程中解密历史密码并使用任何方法来查找密码相似性。
从理论上讲,使用加密存储以前的密码并没有太大的风险。既是因为加密在正确实施时确实工作得很好,而且因为旧密码不再有效,所以知道它不应该为攻击者提供太多优势。在您实施了防止当前密码和过去密码相似的措施后尤其如此。
我完全认识到有些人可能不认为这是一个可接受的替代方案,因为它会使密码历史的泄露风险稍大一些。然而,正如本文所解释的那样,我并不是唯一一个看到在这种情况下使用加密的好处的人。