Java 为什么Spring Security使用默认的预验证检查?

Java 为什么Spring Security使用默认的预验证检查?,java,spring,security,spring-security,Java,Spring,Security,Spring Security,我最近在我雇主的一个基于Spring的Java应用程序中实现了一些安全性改进,我覆盖了Spring security的AbstractUserDetailsAuthenticationProvider类,以便围绕用户身份验证进行一些额外的处理。在此过程中,我意识到,DefaultPreAuthenticationChecks内部类在身份验证提供程序运行验证密码的additionalAuthenticationChecks方法之前执行用户帐户检查。如果用户被禁用、过期或锁定,将引发异常,因此相关消

我最近在我雇主的一个基于Spring的Java应用程序中实现了一些安全性改进,我覆盖了Spring security的
AbstractUserDetailsAuthenticationProvider
类,以便围绕用户身份验证进行一些额外的处理。在此过程中,我意识到,
DefaultPreAuthenticationChecks
内部类在身份验证提供程序运行验证密码的
additionalAuthenticationChecks
方法之前执行用户帐户检查。如果用户被禁用、过期或锁定,将引发异常,因此相关消息将显示在屏幕上。对我来说,在成功验证密码之前检查用户帐户并提供该帐户的详细信息是一个明显的安全风险,因为这可能会暴露用户帐户是否存在。有人知道为什么Spring Security会这样做吗?显然,我可以通过使用一个什么都不做的
check
方法创建自己的虚拟类来覆盖
DefaultPreAuthenticationChecks
类,但遗憾的是,首先必须这样做

提前谢谢


另外,我在一张相关的便笺上发现了一个问题,但似乎没有人问这个问题,为什么会存在这种潜在的安全漏洞。

我想我参加聚会有点晚了,但如果有人还在想,社区实际上已经

引自开发商

卢克·泰勒说:

事实并非如此。这取决于你向他们展示什么样的失败信息 登录失败时的用户–没有什么可以阻止你说 无论原因为何,“登录失败”。这种情况也不少见 应用程序通知用户其帐户在 固定的登录尝试次数。期望的行为将取决于 您如何解释不同的状态标志(这不是 由框架严格定义)。例外情况也会驱动 AuthenticationManager生成的事件,因此它们不是 用户的消费必然存在。系统管理员可能希望 任何时候有人试图使用锁定或禁用的 例如,帐户,而不仅仅是当他们使用正确的密码时

也可以说,在注册帐户之前先检查密码 锁定状态,仅当正确的 给出的密码还允许暴力密码检查,甚至 在帐户被锁定之后

因此,我不同意这种行为是“不正确的”。我想可能是的 不过,能够定制东西很有用。也许我们应该 方法

预验证检查(用户详细信息用户)

后身份验证(UserDetails用户)

当使用不同的标志时,可以覆盖该标志以进行更改 检查过了


tl;dr:社区意识到了这个问题,但他们不认为这是一个潜在的安全缺陷,相反,他们认为这取决于“如何解释不同的状态标志”,是的,使用
setPostAuthenticationChecks(UserDetailsChecker postAuthenticationChecks)很容易更改默认行为
设置预验证检查(UserDetailsChecker preAuthenticationChecks)

这显然是为了性能优化。此外,在检查密码是否正确之前检查禁用或锁定的帐户更安全,反之亦然

正如Neil所提到的,如果您以前做过其他检查,那么就可以避免像bcrypt这样昂贵的操作

因此,让我们考虑第二点,即安全关注。考虑您的应用程序首先检查密码,如果密码有效,则执行其他检查,例如帐户被锁定/禁用等。 潜在的黑客理解这种行为并使用暴力破解用户密码不会花费太长时间,因为他知道只有在密码正确的情况下才会显示帐户锁定/禁用消息

现在回到您所关心的问题,即使用这种方法存在暴露用户帐户是否存在的风险。首先,我认为破解密码的风险大于暴露该帐户存在与否的风险。其次,应用程序可以捕获这些检查(锁定/禁用)引发的异常,并提供自定义消息。例如

catch(LockedException e){
  // log actual reason, so that it could be used for debugging purpose
  return "Invalid credentials"; // or throw BadCrentials exception
}

更多详细信息,请参见:

可能是性能问题。如果用户被禁用,那么不要执行昂贵的bcrypt操作?这是一个很好的观点,但我宁愿先进行检查,这样我们就可以确保尝试访问该帐户的人至少知道密码。那么我们就可以放心了,因为它很可能是授权账户持有人,所以我们可以很高兴地告诉他们,该账户不幸被锁定或禁用。我想这是一个速度的选择,而不是额外的安全性和处理。每当涉及到身份验证时,我都会选择后者!