Frank Zinner bio photo

Frank Zinner

I'm a passionated senior software developer ...

Twitter Facebook LinkedIn Github Xing

Play2 - implementing a CSRF token mechanism

Recently I stumbled over a security issue with some of my web applications. So I decided to dig a bit deeper in how play2 in version 2.3.x handles cross site request forgery attacks and a came up with this little article.

Since version 2.1 of the play framework it has the ability to use filters and with these filters they also support CSRF tokens.

I will give a brief introduction to what is necessary for a play2 application to protect against this vulnerability.

First of all we need the filter dependency for scalas build tool - sbt. So include it in plays build.sbt config file.

libraryDependencies += filters

alternative you can put the configuration in an already existing dependency sequence:

librarayDependencies ++= Seq(..., filters, ...)

Second we need to modify the Global-Object for our application. So extend it from a class called WithFilters. I also added the SecurityHeadersFilter but this isn’t necessary for this example.

object Global extends WithFilters(CSRFFilter(), SecurityHeadersFilter()) with GlobalSettings { ... }

So the Global-Object extends WithFilters and adds the trait GlobalSettings. In the WithFilters class we add a CSRFFilter and a SecurityHeadersFilter.

Now we can prepare our actions in our controller class:

In scala we need an implicit parameter and a CSRF-Token which we can obtain on the CSRF Object with the getToken(request) method. This method needs an implicit request we can hand over to the CSRF class. This generated token will then be given to our template where we use the token to protect our forms.

The code for a simple controller could look like this:

package controllers
import play.api.mvc._ 
object Application extends Controller {
 def index = Action { implicit request =>
   import play.filters.csrf._    val token = CSRF.getToken(request)
   Ok(views.html.index())
 }
 def process = Action { implicit request =>
   Ok("Success")
 }
}

The last step would be to provide the template with our newly created token. For this to work we need the implicit request headers. So add an implicit request header to the template. I also imported the helper package for convenience:

@()(implicit requestHeader: RequestHeader)
@import helper._ 

The form tag can be created with one of the imported helpers:

@form(CSRF(routes.Application.process()), 'enctype -\> "multipart/form-data") {
}
@form(routes.Application.process(), 'enctype -\> "multipart/form-data") {
@CSRF.formField
}

That’s all we need to implement the mechanism. I will now show you some configuration options to customize the tokens. Put these configurations in the application.conf file. The options listed below are the defaults, so feel free to override them for your needs.

# CSRF configuration
csrf.token.name=csrfToken
csrf.cookie.name=csrfCookie
csrf.cookie.secure=true
csrf.sign.tokens=true

Earlier I mentioned the SecurityHeaderFilter which sets a few useful HTTP headers. Below are the default settings if you don’t override or set them. These settings are the most restrictive ones and can be set in the application.conf file.

These are the headers you can set:

  • Content-Security-Policy:default-src ‘self’
  • X-Content-Type-Options:nosniff
  • X-Frame-Options:DENY
  • X-Permitted-Cross-Domain-Policies:master-only
  • X-XSS-Protection:1; mode=block

And here are the configurations for them:

# Security headers this are the defaults
play.filters.headers.frameOptions=DENY
play.filters.headers.xssProtection="1; mode=block"
play.filters.headers.contentTypeOptions="nosniff"
play.filters.headers.permittedCrossDomainPolicies="master-only"
play.filters.headers.contentSecurityPolicy="default-src"

I hope this short article will help someone with similar problems.