错误密码或用户名的一般错误消息 - 这真的有用吗?

信息安全 验证 密码 用户枚举
2021-09-06 06:30:32

当用户尝试登录时,如果用户名或密码错误,则不显示在登录页面上是很常见的(我会说这是某种安全基础)。应该显示一条通用消息,例如“密码或用户名错误”。

原因不是向潜在的攻击者显示哪些用户名已被使用,因此“破解”现有帐户会更加困难。

对我来说听起来很合理,但后来我想到了一些不同的东西。

当您注册您的帐户时,您输入您的用户名。当它已经被占用时,您会收到一条错误消息 - 这不是通用的!

所以基本上,攻击者可以从注册页面中获取“正确”的用户名,还是我错了?

那么通用消息的意义何在?非通用消息会带来更好的用户体验。

4个回答

不,你是对的,在努力防止攻击者确定有效用户身份的过程中,你要么必须对他们撒谎,要么提供异常模糊的错误消息。

您的应用程序可以告诉用户“请求的用户名不可用”,而不是具体说明它是否已在使用或只是不满足您的其他用户名要求(长度、字符使用、保留字等)。当然,如果这些详细信息是公开的,那么攻击者可能会发现他们的猜测失败是由于帐户正在使用而不是由于格式无效。

然后你也有你的密码重置系统。您是否接受任何用户名/电子邮件地址并说即使该帐户不在您的数据库中也已发送消息?帐户锁定(如果您正在使用它)呢?您是否只是告诉用户他们的凭据无效,即使他们不是,而是他们的帐户被锁定,希望他们联系可以识别问题的客户支持?

增加攻击者收集有效用户名的难度是有益的,但通常是以挫败用户为代价的。我见过的大多数安全性较低的网站都使用单独的消息来识别用户名或密码是否错误,只是因为他们宁愿为了让用户满意而犯错。您必须确定您的安全要求是否要求将它们优先于用户体验。

您假设系统实际上知道哪个字段输入不正确。有几个原因这不一定是真的。

一种可能性是它是实施的副作用。在数据库中查找登录名的简单方法可能类似于(使用:n用户提供的参数):

SELECT 1
  FROM users
 WHERE username=:1 AND
       password=HASHING_FUNCTION(CONCAT(:2, salt))

如果你得到一个空的结果,你知道登录应该失败,但你不知道为什么,除非你做一些更复杂的事情或进行另一个查询。因此,有时可能只是懒惰或希望在数据库上轻松一点,而不是有意识的安全决定。

但是即使实现可以区分不存在的用户和不正确的凭据,您仍然会遇到用户正确输入密码但用户名错误的情况,并且恰好是存在的用户(使用不同的密码)。然后,如果用户收到一条消息说他们的密码不正确,那就是错误的。因此,除非指定的用户名不存在,否则系统实际上无法知道是用户名还是密码错误。

一般来说,暴力破解注册页面比暴力破解登录页面更难,所以我们从这个额外的成本中受益。但是,从概念上讲,您是正确的。除了登录页面消息之外,还有其他方法可以枚举用户名。

保持登录失败消息的通用性只是“良好实践”(TM),以使攻击者更难从坏账中收集好账户。使用暴力破解工具,尝试随机名称很简单,然后当错误消息更改时,开始暴力破解该用户名。

但是,与往常一样,您需要在可用性与减少威胁之间取得平衡。

并非所有系统都有帐户注册。例如,您的操作系统登录没有。网站确实不时停止接受新成员。

这是一个关注点分离的问题:登录对话框是否应该根据系统是否配置为接受新帐户的申请来查询系统配置并自定义其行为?然后登录对话框与与其工作无关的信息相耦合。

在所有情况下只实现模糊的错误消息似乎更容易(假设 UI 软件甚至知道是密码错误还是帐户不存在:如果它从某些较低级别的 API 获得一般身份验证错误怎么办?)

而且,还有:新的用户应用程序 UI 可以实现一个较长的假延迟,例如“正在搜索用户群……[10 秒]……哎呀,用户名已经被占用了!” 如果实现了,则意味着通过这种机制探测用户ID的空间是严重限速的。由于申请新帐户是一项罕见的一次性操作,因此用户将遭受延迟,而在常规登录对话框中,他们会因延迟 10 秒而变得更糟。