假设我有一个系统,其中一项安全要求是阻止用户选择与其用户名匹配的密码。用户名不区分大小写,但密码是。服务器使用无法逆转的安全散列函数存储密码。
创建帐户时,用户名和密码最初都以明文形式提供给服务器进行比较。我们可以在内存中比较它们(不考虑大小写)以查看它们是否匹配,如果匹配,则指示用户选择不同的密码。一旦满足此检查,密码就会被安全地散列以进行存储,而用户名则以明文形式存储。在这里满足要求没有问题。
当用户想要更改他们的密码或正在为他们更改密码时,服务器可以检索他们的用户名记录并将其与新选择的密码值进行比较(再次忽略大小写)以查看它是否匹配。在这里满足要求也没有问题。
但是,系统也允许更改用户名。在此 ID 更改过程中,用户不必以明文形式向服务器提供密码。他们在进行身份验证时可能已经这样做了,但服务器不会将该密码以明文形式保存,以防万一他们决定更改用户名。因此,明文密码不可用于检查与新选择的用户名值是否匹配。
为了满足我们的要求,服务器可以使用相同的安全散列函数来散列新用户名并将其与记录的散列密码进行比较。如果它们匹配,则服务器可以指示用户选择不同的用户名。但是,由于用户名不区分大小写,因此当它可能为真时,此检查可能会失败。如果我提交“PwdRsch1”作为新的用户名选择并且我的密码是“pwdrsch1”,那么系统将允许它,因为哈希值不匹配。我——或者更糟糕的是,攻击者——随后可以使用匹配的用户名和密码“pwdrsch1”成功进行身份验证。
我们可以在散列和检查密码之前强制用户名小写,但是相反的情况是可能的。用户名将根据密码“PwdRsch1”检查为“pwdrsch1”并允许,因为它们不匹配。但后来我可以使用匹配的用户名和密码“PwdRsch1”成功进行身份验证。
我有哪些合理的选择来降低密码与不区分大小写的用户名匹配的风险?