Documentation

You are viewing the documentation for the 2.4.8 release in the 2.4.x series of releases. The latest stable release series is 3.0.x.

§Protecting against Cross Site Request Forgery

Cross Site Request Forgery (CSRF) is a security exploit where an attacker tricks a victim’s browser into making a request using the victim’s session. Since the session token is sent with every request, if an attacker can coerce the victim’s browser to make a request on their behalf, the attacker can make requests on the user’s behalf.

It is recommended that you familiarise yourself with CSRF, what the attack vectors are, and what the attack vectors are not. We recommend starting with this information from OWASP.

Simply put, an attacker can coerce a victim’s browser to make the following types of requests:

An attacker can not:

Since GET requests are not meant to be mutative, there is no danger to an application that follows this best practice. So the only requests that need CSRF protection are POST requests with the above mentioned content types.

§Play’s CSRF protection

Play supports multiple methods for verifying that a request is not a CSRF request. The primary mechanism is a CSRF token. This token gets placed either in the query string or body of every form submitted, and also gets placed in the user’s session. Play then verifies that both tokens are present and match.

To allow simple protection for non browser requests, such as requests made through AJAX, Play also supports the following:

§Applying a global CSRF filter

Play provides a global CSRF filter that can be applied to all requests. This is the simplest way to add CSRF protection to an application. To enable the global filter, add the Play filters helpers dependency to your project in build.sbt:

libraryDependencies += filters

Now add them to your Filters class:

import play.http.HttpFilters;
import play.api.mvc.EssentialFilter;
import play.filters.csrf.CSRFFilter;
import javax.inject.Inject;

public class Filters implements HttpFilters {

    @Inject CSRFFilter csrfFilter;

    @Override
    public EssentialFilter[] filters() {
        return new EssentialFilter[] { csrfFilter };
    }
}

The Filters class can either be in the root package, or if it has another name or is in another package, needs to be configured using play.http.filters in application.conf:

play.http.filters = "filters.MyFilters"

§Getting the current token

The current CSRF token can be accessed using the CSRF.getToken method. It takes a RequestHeader, which can be obtained by calling Controllers.request():

Optional<CSRF.Token> token = CSRF.getToken(request());

To help in adding CSRF tokens to forms, Play provides some template helpers. The first one adds it to the query string of the action URL:

@import helper._

@form(CSRF(routes.ItemsController.save())) {
    ...
}

This might render a form that looks like this:

<form method="POST" action="/items?csrfToken=1234567890abcdef">
   ...
</form>

If it is undesirable to have the token in the query string, Play also provides a helper for adding the CSRF token as hidden field in the form:

@form(routes.ItemsController.save()) {
    @CSRF.formField
    ...
}

This might render a form that looks like this:

<form method="POST" action="/items">
   <input type="hidden" name="csrfToken" value="1234567890abcdef"/>
   ...
</form>

§Adding a CSRF token to the session

To ensure that a CSRF token is available to be rendered in forms, and sent back to the client, the global filter will generate a new token for all GET requests that accept HTML, if a token isn’t already available in the incoming request.

§Applying CSRF filtering on a per action basis

Sometimes global CSRF filtering may not be appropriate, for example in situations where an application might want to allow some cross origin form posts. Some non session based standards, such as OpenID 2.0, require the use of cross site form posting, or use form submission in server to server RPC communications.

In these cases, Play provides two actions that can be composed with your applications actions.

The first action is the play.filters.csrf.RequireCSRFCheck action which performs the CSRF check. It should be added to all actions that accept session authenticated POST form submissions:

@RequireCSRFCheck
public Result save() {
    // Handle body
    return ok();
}

The second action is the play.filters.csrf.AddCSRFToken action, it generates a CSRF token if not already present on the incoming request. It should be added to all actions that render forms:

@AddCSRFToken
public Result get() {
    return ok(form.render());
}

§CSRF configuration options

The full range of CSRF configuration options can be found in the filters reference.conf. Some examples include:

Next: Working with Json