Spring CSRF overrides POST logoff behavior in XML security configuration

We currently have a problem with the Spring CSRF solution for our legacy application, because the CSRF implementation changes the default behavior of Spring security Spring sis security configuration:

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

org.springframework.security.config.annotation.web.configurers.LogoutConfigurer The output configurator. According to the Spring documentation:

Adding CSRF will update LogoutFilter only to use HTTP POST. This ensures that a CSRF token is required to exit the system and that an attacker cannot force users to log out of the system.

The code that makes this change is as follows:

  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; } 

Typically, this behavior makes sense to protect CSRF. But it’s very strange for me that this implementation is not flexible (why are hard variables of real implementations, not autowire dependencies?).

The problem is that our application is built in such a way that before performing a regular Spring exit, it performs additional cleanup in the Spring controllers. Basically, the Switch User function is implemented, but in its own way. Thus, changing the logout path to perform POST is not an option, because basically the cleanup is done on the user controller.

There seems to be only one possible solution to use this approach:

 @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 } 

// If he decided to log out, this will go to this controller method:

  @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 } 

Typically, this approach is not good in terms of code quality. So there are two questions:

  • What is the reason for such a strict implementation in Spring and does not give a visible opportunity to override it (in particular, I gave an example of the code how it was created)?
  • Any good alternative to fix the mentioned problem.
+8
java spring spring-security csrf
source share
3 answers

The behavior you describe is behavior if you do not explicitly configure output support, but only enable it, you explicitly configure it, it will use this configuration instead.

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

This is also documented in the reference guide.

However, the real solution to imho is that you should not use the controller for additional output functions, but use LogoutHandler instead . This will work just fine with Spring Security, and you don't need to redirect / forward different urls.

+8
source share

Basically, the main difficulty was overriding logoutFilter in Spring's XML security context to work with the default implementation of org.springframework.security.web.util.matcher.AntPathRequestMatcher (which works with "GET" rather than "POST" requests). To do this, several beans have been added to the xml security context:

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

and the output filter itself:

 <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> 
+4
source share

I saw the same error after updating Internet Explorer 11. CsrfConfigurer.class is not null and a message is expected when you log out.

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

I solved my problem bypassing logoutfilter and inserting a new filter in spring security

An example is below.

  <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> 
0
source share

All Articles