使用Spring Security进行编程的方法

39

我正在使用 Wicket 作为我的演示层,并且已经将其与 Spring 安全性整合。这是由 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章节Session Fixation Attack Protection表示:

会话固定攻击是一种潜在的风险,恶意攻击者通过访问站点创建一个会话,然后诱使另一个用户使用相同的会话登录(例如,发送一个包含会话标识符作为参数的链接)。Spring Security通过在用户登录时创建新会话来自动防护。如果不需要此保护或它与其他要求冲突,可以使用session-fixation-protection属性控制行为,该属性有三个选项:

  • migrateSession - 创建一个新会话并将现有会话属性复制到新会话中。这是默认设置。
  • none - 什么也不做。原始会话将被保留。
  • newSession - 创建一个新的“干净”会话,不复制现有会话数据。

身份验证有效,但由于我对Spring Security还很新,因此有些问题需要回答:

  • 通常为了登录,我会将身份验证信息POST到j_spring_security_check,让Spring Security执行实际的身份验证代码。我想要防止会话固定攻击,那么像我这样执行编程式登录,会得到此保护吗?如果没有,我需要做什么才能得到它?
  • 如何执行编程式注销?
  • 由于我将使用编程式登录和注销,那么如何禁用Spring拦截这些URL?

更新:对于会话固定攻击保护,似乎我需要调用SessionUtils类中的方法,其签名为startNewSessionIfRequired(HttpServletRequest request, boolean migrateAttributes, SessionRegistry sessionRegistry)

我该如何获取所需的SessionRegistry实例并将其传递给该方法?我找不到任何方法来为其创建别名ID,或如何获取其ID或名称。


奖励将授予首个回答上述三个问题的人。 - user14070
嘿,肯特 - 我回答了问题,你为什么让赏金过期了呢? - Pablojim
抱歉,我有一些个人事务需要处理,所以没能及时登录。 - user14070
请参考此问题和答案以了解更好的程序化登录方法。使用这种方法,所有Spring功能,如会话固定保护,将继续正常工作。 https://dev59.com/7lYN5IYBdhLWcg3wlI3G - goat
6个回答

23

也许这不是你问题的完整答案,但或许可以帮到你。

当你不使用编程登录,而是使用标准登录时调用的代码可以在这里找到:

org.springframework.security.ui.webapp.AuthenticationProcessingFilter

我猜你在你的代码中得到了灵感。它看起来非常相似。

同样,当您在标准方法中访问/j_spring_security_logout 时执行的代码可以在这里找到:

org.springframework.security.ui.logout.LogoutFilter

LogoutFilter调用多个处理程序。我们正在使用的处理程序名为: org.springframework.security.ui.logout.SecurityContextLogoutHandler,因此您可以在您的方法中调用相同的代码。


好答案!:-)我受到了Spring 3.0参考文档的启发(我的try块中的三行代码是直接复制粘贴的):http://static.springframework.org/spring-security/site/docs/3.0.x/reference/technical-overview.html#d4e689。不过需要注意的是,我使用的是2.0.4版本。我会研究你提到的代码!谢谢!我暂时还在寻找一些关于我的原始问题的答案,所以我仍然保持问题开放状态。 - user14070

8
你确实会面临会话固定攻击。为了解决这个问题,你可以再次“受到”Spring代码的启发。要创建一个新会话,你显然需要访问httpsession,因此你可能需要进行一些重构。
如果你看到方法SessionUtils.startNewSessionIfRequired,这将把认证迁移到一个新的会话中。你可以直接调用这个方法,或者稍微重构一下代码。
至于编程注销,当你需要注销用户时,只需简单地调用session.invalidate()即可。从一般安全角度来看,这将完成所有必要的操作,但请注意,你可能需要清理一些会话内容。如果你有一组非常复杂的过滤器等,并且需要确保用户在请求的其余部分中已经注销,则可以添加:
SecurityContextHolder.getContext().setAuthentication(null);

关于拦截URL,你可以将它们设置为未使用的内容并忽略它们!如果你真的想要移除它的话,我不确定你是否可以在配置中关闭拦截 - 如果你真的想要移除它,那么可以看看AuthenticationProcessingFilter - 你可以自定义它。如果这样做,那么你将不得不手动设置Spring Security XML,而不能使用提供的名称空间。不过这并不难 - 看一些旧文档,你就会知道如何做了。希望这能帮到你!

我已经创建了一个更新,因为我在会话固定攻击保护方面遇到了问题。 - user14070
你需要限制会话的并发吗?例如,允许同一用户在两个不同的会话中登录两次。如果不需要,则不需要SessionRegistry - 只需将null值传递到SessionUtils方法中。如果您确实需要此功能,则在实现时将拥有一个sessionRegistry!请参阅此处:http://static.springframework.org/spring-security/site/docs/2.0.x/reference/ns-config.html#ns-concurrent-session同样地,对于您,您可能需要自己配置它而不是使用自定义命名空间。我猜您不需要此功能。 - Pablojim
SessionUtils在spring-security 3.0中已被删除,看起来org.springframework.security.web.authentication.session.SessionFixationProtectionStrategy.onAuthentication()(以及它的子类ConcurrentSessionControlStrategy)是它最接近的替代品。 - Stefan L

6

1) 编程登出

  1. 调用 HttpServletRequest.getSession(false).invalidate
  2. 调用 SecurityContextHolder.clearContext()

2) 告诉Spring Security不要拦截某些URL,这取决于您的应用程序URL空间的设置。如果除了 /logIn 和 /logout 之外的所有页面都位于上下文 /myApp 中,则可以执行以下操作:

<http ....>
  <intercept-url pattern="/myApp/**" ..>
 ....
</http>

1

我在程序化登录方面遇到了问题。我调用了全部的 authenticationManager.authenticate(...)SecurityContextHolder.getContext().setAuthentication(...) 方法,但是在 Session 方面出现了一些问题。为了正确管理会话,我不得不添加以下几行代码:

HttpSession session = request.getSession();
session.setAttribute("SPRING_SECURITY_CONTEXT", SecurityContextHolder.getContext());

从上面张贴的示例代码中并不清楚。有关详细信息,请查看http://forum.springsource.org/showthread.php?t=69761


0
你可以试试这个。
    try {
        HttpSession session = request.getSession(false);
        if (session != null) {
            session.invalidate();
        }

        SecurityContextHolder.clearContext();

    } catch (Exception e) {
        logger.log(LogLevel.INFO, "Problem logging out.");
    }

0
进行编程式注销也可以抛出org.springframework.security.core.AuthenticationException。例如,SessionAuthenticationException。在这种情况下,ExceptionTranslationFilter会启动注销。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接