springspring-mvcspring-securitycsrf

Session timeout leads to Access Denied in Spring MVC when CSRF integration with Spring Security


I have Integrated CSRF token with Spring Security in my Spring MVC Project. Everything works properly with CSRF token, token will be sent from client side to server side.

I have changed my logout process to make its POST method send CSRF token and it works fine.

I have faced a problem when session timeout is occurred, it needs to be redirected to spring default logout URL but it gives me Access Denied on that URL.

How to override this behavior?

I have included below line in Security config file

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

Please let me know if anyone needs more information.


Solution

  • The question is a bit old, but answers are always useful.

    First, this is a known issue with session-backed CSRF tokens, as described in the docs: CSRF Caveats - Timeouts.

    To solve it, use some Javascript to detect imminent timeouts, use a session-independent CSRF token repository or create a custom AccessDeniedHandler route. I chose the latter:

    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. */
            }
        }
    }
    

    Alternatively, you can define the custom handler as a 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>