簡體   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