Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Could not verify the provided CSRF token. Using only xml

Tags:

I'm in the process of learning Spring framework, and I'm using xml configuration file for the security:

<security:http once-per-request="false" use-expressions="true">
    <!-- <security:intercept-url pattern="/admin" access="hasAuthority('ROLE_ADMIN')" /> -->
    <security:intercept-url pattern="/admin" access="permitAll" />
    <security:intercept-url pattern="/createoffer" access="isAuthenticated()" />
    <security:intercept-url pattern="/docreateoffer" access="isAuthenticated()" />
    <security:intercept-url pattern="/offercreated" access="isAuthenticated()" />
    <security:intercept-url pattern="/" access="permitAll" />
    <security:intercept-url pattern="/denied" access="permitAll" />     
    <security:intercept-url pattern="/loggedout" access="permitAll" />
    <security:intercept-url pattern="/newaccount" access="permitAll" />
    <security:intercept-url pattern="/createaccount" access="permitAll" />
    <security:intercept-url pattern="/accountcreated" access="permitAll" />
    <security:intercept-url pattern="/static/**" access="permitAll" />
    <security:intercept-url pattern="/login" access="permitAll" />
    <security:intercept-url pattern="/offers" access="permitAll" />
    <security:intercept-url pattern="/**" access="denyAll" />
    <security:form-login login-page="/login" authentication-failure-url="/login?error=true" />
    <security:logout logout-success-url="/loggedout" logout-url="/logout"/>
    <security:remember-me key="offersAppKey"
        user-service-ref="jdbcUserService"
        remember-me-parameter="remember-me" token-validity-seconds="1209600" />
</security:http>

and in my login form:

<form name='f' action='${pageContext.request.contextPath}/login'
    method='POST'>
    <table>
        <tr>
            <td>User:</td>
            <td><input type='text' name='username' value=''></td>
        </tr>
        <tr>
            <td>Password:</td>
            <td><input type='password' name='password' /></td>
        </tr>
        <tr>
            <td>Remember Me</td>
            <td><input type="checkbox" checked="checked" name="remember-me" /></td>
        </tr>
        <tr>
            <td colspan='2'><input name="submit" type="submit"
                value="Login" /></td>
        </tr>
        <input type="hidden" name="${_csrf.parameterName}"
            value="${_csrf.token}" />
    </table>
</form>

But after I log in and some time passes (I set the session timeout to be 1 minute in the web.xml) I get this error in the browser:

Could not verify the provided CSRF token because your session was not found.

So far, I couldn't find any post that only uses the xml file for the configuration. It's all about configuring using java and some other answers suggest that to include csrf hidden input in the login form, which I already do. Any idea how to fix this issue ?

P.S.: the web.xml file looks like this:

<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://xmlns.jcp.org/xml/ns/javaee" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd" id="WebApp_ID" version="3.1"> <display-name>spring-tutorial-51</display-name> <description>Spring tutorial web app</description> <welcome-file-list> <welcome-file>index.html</welcome-file> <welcome-file>index.htm</welcome-file> <welcome-file>index.jsp</welcome-file> <welcome-file>default.html</welcome-file> <welcome-file>default.htm</welcome-file> <welcome-file>default.jsp</welcome-file> </welcome-file-list> <servlet> <description></description> <display-name>offers</display-name> <servlet-name>offers</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>offers</servlet-name> <url-pattern>/</url-pattern> </servlet-mapping> <resource-ref> <description>DB Connection</description> <res-ref-name>jdbc/springtutorial</res-ref-name> <res-type>javax.sql.DataSource</res-type> <res-auth>Container</res-auth> </resource-ref> <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener> <context-param> <param-name>contextConfigLocation</param-name> <param-value> classpath:com/myproject/spring/web/config/dao-context.xml classpath:com/myproject/spring/web/config/service-context.xml classpath:com/myproject/spring/web/config/security-context.xml </param-value> </context-param> <filter> <display-name>springSecurityFilterChain</display-name> <filter-name>springSecurityFilterChain</filter-name> <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class> </filter> <filter-mapping> <filter-name>springSecurityFilterChain</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> <session-config> <session-timeout>1</session-timeout> </session-config> </web-app>

I added the following config to my security config file.

I added this to my security-context.xml which is a config file for security.

<security:remember-me key="offersAppKey"
user-service-ref="jdbcUserService"
remember-me-parameter="remember-me" token-validity-seconds="1209600" />

And I expect to have the token valid after 1 minute for 1209600 seconds.

like image 773
Arian Avatar asked Feb 20 '17 00:02

Arian


1 Answers

I don't understand where is the suprising part here? You said that

I set the session timeout to be 1 minute in the web.xml

Where else the server can store its copy of your CSRF-token except for your session? So when in a minute your session expires, the server can't find its copy to match CSRF-token in your request and raises such an exception.

I think you can see relevant code around https://github.com/spring-projects/spring-security/blob/master/web/src/main/java/org/springframework/security/web/csrf/CsrfFilter.java#L113 and https://github.com/spring-projects/spring-security/blob/master/web/src/main/java/org/springframework/security/web/csrf/HttpSessionCsrfTokenRepository.java#L75

So to fix the issue just increase your session timeout. (Timeout of only 1 minute seems incredibly strict to me. I haven't seen anything less than 10 minutes in real life even in "secure" places and typically much more.)

like image 104
SergGr Avatar answered Sep 23 '22 10:09

SergGr