2014-12-26 8 views
8

Ich habe CSRF-Token mit Spring Security in meinem Spring MVC-Projekt integriert. Alles funktioniert ordnungsgemäß mit CSRF-Token, Token wird von Client-Seite an Server-Seite gesendet.Session-Timeout führt zu Access im Frühjahr MVC verweigert, wenn CSRF Integration mit Spring Security

Ich habe meine logout Prozess geändert, um es POST Methode, CSRF-Token zu senden, und es funktioniert gut.

Ich habe Gesicht Problem, wenn Sitzungs-Timeout aufgetreten ist, muss es um Frühjahr Standard-Logout-URL umgeleitet werden, aber es gibt mir Access Denied auf dieser URL.

So überschreiben Sie dieses Verhalten.

Ich habe umfassen unter der Linie in Sicherheitskonfigurationsdatei

<http> 
     //Other config parameters 
     <csrf/> 
    </http> 

Bitte lassen Sie mich wissen, ob jemand mehr Informationen benötigt.

Antwort

12

Die Frage ist ein bisschen alt, aber Antworten sind immer nützlich.

Zuerst ist dies ein bekanntes Problem mit session-backed CSRF-Tokens, wie in der Dokumentation beschrieben: CSRF Caveats - Timeouts.

Verwenden Sie Javascript, um drohende Timeouts zu erkennen, verwenden Sie ein sessionunabhängiges CSRF-Token-Repository oder erstellen Sie eine benutzerdefinierte AccessDeniedHandler-Route. Ich entschied mich für letzteres:

Config XML:

<http> 
    <!-- ... --> 
    <access-denied-handler ref="myAccessDeniedHandler"/> 
</http> 

<bean id="myAccessDeniedHandler" class="package.MyAccessDeniedHandler"> 
    <!-- <constructor-arg ref="myInvalidSessionStrategy" /> --> 
</bean> 

MyAccessDeniedHandler:

public class MyAccessDeniedHandler implements AccessDeniedHandler { 
    /* ... */ 
    @Override 
    public void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException exception) 
      throws IOException, ServletException { 
     if (exception instanceof MissingCsrfTokenException) { 
      /* Handle as a session timeout (redirect, etc). 
      Even better if you inject the InvalidSessionStrategy 
      used by your SessionManagementFilter, like this: 
      invalidSessionStrategy.onInvalidSessionDetected(request, response); 
      */ 
     } else { 
      /* Redirect to a error page, send HTTP 403, etc. */ 
     } 
    } 
} 

Alternativ können Sie die benutzerdefinierten Handler als DelegatingAccessDeniedHandler definieren:

<bean id="myAccessDeniedHandler" class="org.springframework.security.web.access.DelegatingAccessDeniedHandler"> 
    <constructor-arg name="handlers"> 
     <map> 
      <entry key="org.springframework.security.web.csrf.MissingCsrfTokenException"> 
       <bean class="org.springframework.security.web.session.InvalidSessionAccessDeniedHandler"> 
        <constructor-arg name="invalidSessionStrategy" ref="myInvalidSessionStrategy" /> 
       </bean> 
      </entry> 
     </map> 
    </constructor-arg> 
    <constructor-arg name="defaultHandler"> 
     <bean class="org.springframework.security.web.access.AccessDeniedHandlerImpl"> 
      <property name="errorPage" value="/my_error_page"/> 
     </bean> 
    </constructor-arg> 
</bean> 
+0

Dank ... Ich kann es schon getan .. –

0

Die Antwort zur Verfügung gestellt von mdrg ist genau richtig, und ich habe auch eine benutzerdefinierte AccessDeniedHandler implementiert Ich lege für Ihre Überlegung:

import java.io.IOException; 
import javax.servlet.ServletException; 
import javax.servlet.http.HttpServletRequest; 
import javax.servlet.http.HttpServletResponse; 
import javax.servlet.http.HttpSession; 
import org.springframework.security.access.AccessDeniedException; 
import org.springframework.security.web.access.AccessDeniedHandlerImpl; 
import org.springframework.security.web.csrf.MissingCsrfTokenException; 
import org.springframework.security.web.savedrequest.HttpSessionRequestCache; 
import org.springframework.security.web.savedrequest.RequestCache; 

/** 
* Intended to fix the CSRF Timeout Caveat 
* (https://docs.spring.io/spring-security/site/docs/current/reference/htmlsingle/#csrf-timeouts). 
* When the session expires and a request requiring CSRF is received (POST), the 
* missing token exception is handled by caching the current request and 
* redirecting the user to the login page after which their original request will 
* complete. The intended result is that no loss of data due to the timeout will 
* occur. 
*/ 
public class MissingCsrfTokenAccessDeniedHandler extends AccessDeniedHandlerImpl { 
    private RequestCache requestCache = new HttpSessionRequestCache(); 
    private String loginPage = "/login"; 

    @Override 
    public void handle(HttpServletRequest req, HttpServletResponse res, AccessDeniedException exception) throws IOException, ServletException { 
    if (exception instanceof MissingCsrfTokenException && isSessionInvalid(req)) { 
     requestCache.saveRequest(req, res); 
     res.sendRedirect(req.getContextPath() + loginPage); 
    } 
    super.handle(req, res, exception); 
    } 

    private boolean isSessionInvalid(HttpServletRequest req) { 
    try { 
     HttpSession session = req.getSession(false); 
     return session == null || !req.isRequestedSessionIdValid(); 
    } 
    catch (IllegalStateException ex) { 
     return true; 
    } 
    } 

    public void setRequestCache(RequestCache requestCache) { 
    this.requestCache = requestCache; 
    } 

    public void setLoginPage(String loginPage) { 
    this.loginPage = loginPage; 
    } 
} 

über Java-Config verdrahtet:

@EnableWebSecurity 
public class SecurityConfig extends WebSecurityConfigurerAdapter { 

    @Override 
    protected void configure(HttpSecurity http) throws Exception { 
    ... 
    http.exceptionHandling().accessDeniedHandler(getAccessDeniedHandler()); 
    ... 
    } 

    public AccessDeniedHandler getAccessDeniedHandler() { 
    return new MissingCsrfTokenAccessDeniedHandler(); 
    } 
}