Spring-security: CsrfRequestDataValueProcessor triggers session creation when response is committed

Created on 30 May 2016  路  3Comments  路  Source: spring-projects/spring-security

Summary

CsrfRequestDataValueProcessor takes care of adding a hidden form input field with the CSRF token value for POST forms. This is done in the getExtraHiddenFields() method. When there is no active session (i.e. anonymous user), this triggers a session creation. If some output has already been written to the response (i.e. it's "committed") prior to this and cookies are used to store the session id, this exception occurs:

java.lang.IllegalStateException: Cannot create a session after the response has been committed

Actual Behavior

In Thymeleaf (3), this can occur: (see https://github.com/thymeleaf/thymeleaf-spring/issues/110) in certain conditions:

  1. Writing 16kb before the form (buffer size with Spring Boot embedded Tomcat)
  2. Thymeleaf's inline serializing uses Jackson. Jackson flushes its buffer after serialization.

I have no experience with JSP, but a quick search suggests that flushing output before the whole page is processed is also possible.

I expect other view renderers using CsrfRequestDataValueProcessor can also exhibit this kind of behavior.

Requesting a CSRF token when rendering a form while no session is active is probably a common case when GETting login forms.

Workaround

The obvious workaround is to make sure a session is created for any page containing a form which can be accessed anonymously.

Expected Behavior

I haven't been able (yet) to find anything better than my current workaround to solve this issue. Hopefully someone will have a better idea how to solve this.

Version

Spring Boot 1.3.5 with Thymeleaf 3

stackoverflow

Most helpful comment

@berniegp Thanks for the feedback.

As you suggested, the only thing you can really do to prevent this is to eagerly create the CsrfToken. In Spring Security 4.1.0.RELEASE+ and Java Configuration you can do this with:

http
        .csrf()
         .csrfTokenRepository(new HttpSessionCsrfTokenRepository())

This tells Spring Security that you do not want the token to be lazily persisted. If you are concerned with creating a session, you can also use the cookie implementation. For example:

http
    .csrf()
        .csrfTokenRepository(new CookieCsrfTokenRepository())

With Spring Boot, you can override the Spring Security version using the information from Customize dependency versions:

build.gradle

 ext['spring-security.version'] = '4.1.0.RELEASE'

pom.xml

<spring-security.version>4.1.0.RELEASE</spring-security.version>

All 3 comments

@berniegp Thanks for the feedback.

As you suggested, the only thing you can really do to prevent this is to eagerly create the CsrfToken. In Spring Security 4.1.0.RELEASE+ and Java Configuration you can do this with:

http
        .csrf()
         .csrfTokenRepository(new HttpSessionCsrfTokenRepository())

This tells Spring Security that you do not want the token to be lazily persisted. If you are concerned with creating a session, you can also use the cookie implementation. For example:

http
    .csrf()
        .csrfTokenRepository(new CookieCsrfTokenRepository())

With Spring Boot, you can override the Spring Security version using the information from Customize dependency versions:

build.gradle

 ext['spring-security.version'] = '4.1.0.RELEASE'

pom.xml

<spring-security.version>4.1.0.RELEASE</spring-security.version>

I'm fairly confident this resolves the issue, so I'm closing this as answered. If you have additional questions, please re-open or create a new ticket :)

Thank you @rwinch!

Was this page helpful?
0 / 5 - 0 ratings