2014-12-26 3 views
8

Spring MVC 프로젝트에 Spring Security와 통합 된 CSRF 토큰이 있습니다. CSRF 토큰으로 모든 것이 제대로 작동하며, 토큰은 클라이언트 측에서 서버 측으로 전송됩니다.스프링 보안과의 CSRF 통합시 세션 시간 초과로 인해 Spring MVC에서 액세스가 거부 됨

logout 프로세스를 변경하여 POST CSRF 토큰을 보내는 방법과 그 작동에 문제가 없습니다.

세션 시간 초과가 발생할 때 얼굴 문제가 발생합니다. 스프링 기본 로그 아웃 URL로 리디렉션해야하지만 해당 URL에 Access Denied이 표시됩니다.

이 동작을 재정의하는 방법

나는이 보안 설정 파일에서 선 아래 포함

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

사람이 더 많은 정보를 필요로하는 경우 알려 주시기 바랍니다.

답변

12

질문은 약간 오래된 것이지만 답변은 항상 유용합니다.

먼저 이것은 세션에서 지원되는 CSRF 토큰과 관련하여 알려진 문제입니다 (문서 : CSRF Caveats - Timeouts에서 설명 됨).

해결하려면 몇 가지 Javascript를 사용하여 절박한 시간 초과를 감지하고 세션 독립적 인 CSRF 토큰 리포지토리를 사용하거나 사용자 지정 AccessDeniedHandler 경로를 만듭니다. 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. */ 
     } 
    } 
} 

, 당신이 DelegatingAccessDeniedHandler으로 사용자 정의 핸들러를 정의 할 수 있습니다

<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

감사합니다 ... 나는 이미 그것을 다 .. –

0

대답은 제공 나는 후자를 선택했다 mdrg가 올바르다. 나는 또한 사용자 정의 AccessDeniedHandler을 구현했다. 나는 당신의 검토를 위해 제출

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

자바 설정을 통해 최대 유선 :

@EnableWebSecurity 
public class SecurityConfig extends WebSecurityConfigurerAdapter { 

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

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