繁体   English   中英

Spring CSRF覆盖安全XML配置中的“POST”注销行为

[英]Spring CSRF override “POST” logout behaviour in security XML config

目前我们的遗留应用程序的Spring CSRF解决方案存在问题,因为CSRF实现更改了默认Spring安全性Spring安全配置的行为:

<http pattern="">
...
<logout
                logout-url="/logout"
                delete-cookies="..."
                success-handler-ref="logoutSuccessHandler"
                />
<csrf/>
</http>

org.springframework.security.config.annotation.web.configurers.LogoutConfigurer注销配置器。 根据Spring文档:

添加CSRF会将LogoutFilter更新为仅使用HTTP POST。 这可确保注销需要CSRF令牌,并且恶意用户无法强制注销您的用户。

进行此更改的代码如下:

 private RequestMatcher getLogoutRequestMatcher(H http) {
        if(logoutRequestMatcher != null) {
            return logoutRequestMatcher;
        }
        if(http.getConfigurer(CsrfConfigurer.class) != null) {
            this.logoutRequestMatcher = new AntPathRequestMatcher(this.logoutUrl, "POST");
        } else {
            this.logoutRequestMatcher = new AntPathRequestMatcher(this.logoutUrl);
        }
        return this.logoutRequestMatcher;
    }

通常,对于CSRF保护,这种行为非常有意义。 但对于我来说,这种实现不灵活(为什么硬编码实际的实现而不是autowire依赖?)是非常奇怪的。

问题是我们的应用程序是这样构建的,即在常规Spring注销之前,它会在Spring Controllers中执行额外的清理。 主要是它实现了Switch User功能,但是以自定义方式实现。 因此,更改注销链接以执行POST不是一种选择,因为主要是在自定义控制器上执行清理。

似乎为了使用指定的方法,只有一种可能的解决方案:

@RequestMapping(value = "/logout", method = RequestMethod.GET) //or it can be a post
    public String logout() {
// 1. Perform Clean up
// 2. Decide whether to logout or redirect to other page
// 3. Perform redirect based on decision
}

//如果决定退出,则会转到此Controller方法:

  @RequestMapping(value = "csrflogout", method = RequestMethod.GET)
    public void csrfLogout(){
//1 Create manual post request
//2. Copy session information
//3. Perform Post to logout URL that is specified in security xml
     }

从代码质量的角度来看,这种方法通常并不好。 所以,有两个问题:

  1. 在Spring中进行如此严格的实现的原因是什么,并且没有提供覆盖它的任何可见的可能性(特别是我提供了代码示例如何创建它)?
  2. 修复上述问题的任何好方法。

您描述的行为是行为,如果您没有显式配置注销支持但只启用它,您明确配置它将使用该配置。

@Override
protected void configure(HttpSecurity http) throws Exception {
    http
        .logout()
            .logoutRequestMatcher(new AntPathRequestMatcher("/logout"));
}

这也被记录在参考指南中。

然而,真正的解决方案是你不应该使用控制器来实现额外的注销功能,而是使用LogoutHandler 这将很好地与Spring Security集成,您不需要重定向/转发到不同的URL。

基本上,主要的复杂性是在Spring Security XML上下文中重写logoutFilter,以使用org.springframework.security.web.util.matcher.AntPathRequestMatcher的默认实现(使用“GET”而不是“POST”请求)。 为了做到这一点,将几个bean添加到安全xml上下文中:

 <bean id="logoutAntPathRequestMatcher" class="org.springframework.security.web.util.matcher.AntPathRequestMatcher">
        <constructor-arg value="logout" />
    </bean>

和注销过滤器本身:

<bean id="logoutFilter"
    class="org.springframework.security.web.authentication.logout.LogoutFilter">
    <constructor-arg  name="logoutSuccessHandler" ref="logoutSuccessHandler"/>
    <constructor-arg  name="handlers">
        <list>
            <ref bean="securityContextLogoutHandler" />
            <ref bean="cookieClearingLogoutHandler" />
            <ref bean="csrfLogoutHandler" />
        </list>
    </constructor-arg>
    <property name="filterProcessesUrl" value="/logout"/>
    <property name="logoutRequestMatcher" ref="logoutAntPathRequestMatcher"/>
</bean>

Internet Explorer 11更新后,我看到了同样的错误。 CsrfConfigurer.class不为null,并且在注销时需要发布。

if(http.getConfigurer(CsrfConfigurer.class) != null) {
            this.logoutRequestMatcher = new AntPathRequestMatcher(this.logoutUrl, "POST");
        } else {
            this.logoutRequestMatcher = new AntPathRequestMatcher(this.logoutUrl);
        }

我通过绕过logoutfilter并插入新的过滤器来解决我的问题

示例如下。

    <beans:bean id="logoutAntPathRequestMatcher" class="org.springframework.security.web.util.matcher.AntPathRequestMatcher">
            <beans:constructor-arg value="/logout"/>
        </beans:bean>

        <beans:bean id="securityContextLogoutHandler" class="org.springframework.security.web.authentication.logout.SecurityContextLogoutHandler">

        </beans:bean>


        <beans:bean id="cookieClearingLogoutHandler" class="org.springframework.security.web.authentication.logout.CookieClearingLogoutHandler">
            <beans:constructor-arg value="JSESSIONID"/>
        </beans:bean>

        <beans:bean id="logoutFilter"
              class="org.springframework.security.web.authentication.logout.LogoutFilter">
            <beans:constructor-arg  name="logoutSuccessUrl" value="/login"/>
            <beans:constructor-arg  name="handlers">
                <beans:list>
                    <beans:ref bean="securityContextLogoutHandler" />
                    <beans:ref bean="cookieClearingLogoutHandler" />
                </beans:list>
            </beans:constructor-arg>
            <beans:property name="filterProcessesUrl" value="/logout"/>
            <beans:property name="logoutRequestMatcher" ref="logoutAntPathRequestMatcher"/>
        </beans:bean>


<http>
...
<sec:custom-filter ref="logoutFilter" after="LOGOUT_FILTER"/>
...
</http>

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM