Spring Security 的编程使用
-
06-07-2019 - |
题
我在用 便门 与我的表示层的 Wicket Auth 项目一起,因此我将其与 Spring Security 集成。这是 Wicket 为我调用的身份验证方法:
@Override
public boolean authenticate(String username, String password) {
try {
Authentication request = new UsernamePasswordAuthenticationToken(
username, password);
Authentication result = authenticationManager.authenticate(request);
SecurityContextHolder.getContext().setAuthentication(result);
} catch (AuthenticationException e) {
return false;
}
return true;
}
我的 Spring Security XML 配置的内容(内部)是:
<http path-type="regex">
<form-login login-page="/signin"/>
<logout logout-url="/logout" />
</http>
<global-method-security secured-annotations="enabled" />
<authentication-manager alias="authenticationManager"/>
<authentication-provider user-service-ref="userService">
<password-encoder ref="bcryptpasswordencoder" />
</authentication-provider>
这部分 2.3.6。会话固定攻击防护 参考文档中说:
在可能的情况下,会话固定攻击是一种潜在风险 让恶意攻击者创建一个 会话,然后 说服其他用户登录 相同的会话(通过向他们发送 包含会话标识符的链接 例如,作为参数)。春天 安全性可防止这种情况发生 通过创建新的 会话。如果你 不需要此保护,或者它 与其他一些要求冲突, 您可以使用以下命令来控制行为 会话固定保护 属性 ,它有三个 选项:
- migrateSession - 创建一个新会话并复制现有的会话 会话属性添加到新会话。这是默认设置。
- 无 - 不要做任何事情。原始会话将被保留。
- newSession - 创建一个新的“干净”会话,而不复制 现有会话数据。
身份验证有效,但由于我对 Spring Security 相当陌生,我有一些问题也需要答案:
- 通常对于登录,我会将身份验证信息发布到
j_spring_security_check
并让 Spring Security 执行实际的身份验证代码。我希望获得针对会话固定攻击的保护,当我像我一样执行编程登录时,我能得到它吗?如果没有,我需要做什么才能得到它? - 如何执行编程注销?
- 由于我将使用编程式登录和注销,如何禁用 Spring 拦截这些 URL?
更新:对于会话固定攻击保护,我似乎需要使用签名调用 SessionUtils 类中的方法 startNewSessionIfRequired(HttpServletRequest request, boolean migrateAttributes, SessionRegistry sessionRegistry)
.
如何获取需要传入的 SessionRegistry 实例?我找不到任何方法来为其创建别名 ID,或者如何获取它的 ID 或名称。
解决方案
也许这不是您问题的完整答案,但也许会对您有所帮助。
当您不使用编程登录时调用的代码,但可以在此处找到标准代码:
org.springframework.security.ui.webapp.AuthenticationProcessingFilter
我猜你的代码中受到了这一点的启发。看起来很相似。
类似地,当您访问时执行的代码 /j_spring_security_logout
在标准方法中,可以在这里找到:
org.springframework.security.ui.logout.LogoutFilter
LogoutFilter 调用多个处理程序。我们使用的处理程序称为:org.springframework.security.ui.logout.SecurityContextLogoutHandler
, ,因此您可以在您的方法中调用相同的代码。
其他提示
您确实会对会话固定攻击持开放态度。为了解决这个问题,您可以再次受到 Spring 代码的“启发”。要创建新会话,您显然需要访问 httpssession,因此您可能需要进行一些重构。
如果你看到这个方法 SessionUtils
.startNewSessionIfRequired
.
这会将身份验证迁移到新会话。您也许可以直接调用此方法,或者只需稍微重构一下代码即可。
至于编程注销,您只需调用就不会犯太大的错误 session.invalidate()
当您需要将该人注销时。从一般安全角度来看,这将执行所有必要的操作,但请记住,尽管您可能需要清理会话中的一些内容。如果您有一组非常复杂的过滤器等。并且您需要确保用户在请求的其余部分中已注销,然后您可以添加:
SecurityContextHolder.getContext().setAuthentication(null);
至于拦截 url,你可以将它们设置为未使用的内容并忽略它!我不确定你是否可以在配置中关闭拦截 - 如果你真的想删除它,那么看看 AuthenticationProcessingFilter
- 你可以定制这个。如果您这样做,那么您将必须手动设置 spring security xml 并且不使用提供的名称空间。不过这并不太难——看看一些旧的文档,你就会知道如何做到这一点。
希望这可以帮助!
1) 程序化注销
- 调用 HttpServletRequest.getSession(false).invalidate
- 调用 SecurityContextHolder.clearContext()
2)告诉Spring Security不要拦截某些URL,这取决于您的应用程序url空间的设置方式。如果您的所有页面(/logIn 和 /logout 除外)都位于上下文 /myApp 中,那么您可以执行以下操作:
<http ....>
<intercept-url pattern="/myApp/**" ..>
....
</http>
我在程序化登录方面遇到了问题。我打电话给所有 authenticationManager.authenticate(...)
和 SecurityContextHolder.getContext().setAuthentication(...)
方法,但会话存在一些问题。我必须添加以下几行才能正确管理会话:
HttpSession session = request.getSession();
session.setAttribute("SPRING_SECURITY_CONTEXT", SecurityContextHolder.getContext());
从上面发布的示例代码中并不清楚这一点。欲了解更多请查看 http://forum.springsource.org/showthread.php?t=69761
要以编程方式注销,也可以抛出 org.springframework.security.core.AuthenticationException
. 。例如, SessionAuthenticationException
. 。在这种情况下 ExceptionTranslationFilter
启动注销。
你可以试试这个
try {
HttpSession session = request.getSession(false);
if (session != null) {
session.invalidate();
}
SecurityContextHolder.clearContext();
} catch (Exception e) {
logger.log(LogLevel.INFO, "Problem logging out.");
}