11
votes

I'm new in Play Framework, and trying to submit the form, but get this error: "p.filters.CSRF - [CSRF] Check failed because no token found in headers" . I'm using Play 2.6, here's my controller code:

    package controllers;

import play.libs.Json;
import play.mvc.*;

import views.html.*;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

public class HomeController extends Controller {

    public Result index() {
        return ok(index.render("Your new application is ready."));
    }

    public Result test() {
        List<String> list = new ArrayList<>();
        list.add("Jobs");
        list.add("Work");
        list.add("Say");
        list.add("Stop");
        return ok(test.render("test", list));
    }

    public Result testPost() {
       Map<String,String[]> form =  request().body().asFormUrlEncoded();
       return ok(Json.toJson(form)).as("application/json");
    }

}

Template:

@(title: String, list: List[String])

@import helper._

<!DOCTYPE html>
<html lang="en">
    <head>
        <title>@title</title>
    </head>
    <body>
        <form action="/test" method="post">
            <textarea name="raw_text">

            </textarea>
            @CSRF.formField
            <input type="submit" value="Submit" />
        </form>
    </body>
</html>

What I am doing wrong?

4

4 Answers

15
votes

I have faced with it. And i solved it very simply. Just add to your application.conf:

play.filters.enabled += "play.filters.csrf.CSRFFilter"

and in the routes file add the nocsrf modifier tag before your route:

+nocsrf
POST        /login                     controllers.AuthController.authorize()

just like that.. I hope my answer help you. Thank you!

3
votes

Duman Zhanbolatov's is a wrong answer. Yes by doing this the error can be avoided but it is not the answer. It will push the app to security flaw.

The reason the application is facing the problem is for the PLAY_SESSION(or your customed session name) cookie of form page request is empty, where csrfToken=value should have been encrypted. Because somehow csrfToken=value in cookies has been removed. It may be happened if you send a response with new-session or discarding cookies. So if you discard cookies or sending response with new-session send it with csrfToken=value session.

def logout: Action[AnyContent] = Action {
    implicit request =>
      val csrfToken = CSRF.getToken.get.value
      
      Ok(logIn("Please log in")).withNewSession.withSession("csrfToken"->csrfToken)

  }  

Then you will get rid of this problem.

0
votes

I couldn't find anything wrong with your code, so set up an identical Play project locally. When submitting the form I do not hit this issue. This is a base project created via:

sbt new playframework/play-java-seed.g8

Posting "Testing testing" as the content of the textArea returns the following Json (as displayed by browser):

raw_text    
0   "            Testing testing"
csrfToken   
0   "8fdc72b2d628e4fc0d8f6359f2ea247cc0f22e5c-1499016237415-3c043ab2a02c18020df21a1f"

The one thing I took from my own projects, is a modified Filters class which looks like this:

import play.mvc.EssentialFilter;
import play.filters.cors.CORSFilter;
import play.http.HttpFilters;
import play.filters.csrf.CSRFFilter;
import play.filters.headers.SecurityHeadersFilter;
import java.util.List;
import javax.inject.Inject;
import javax.inject.Named;
import java.util.Arrays;
public class Filters implements HttpFilters {
    @Inject 
    CSRFFilter csrfFilter;
    @Inject
    CORSFilter corsFilter;
    @Inject 
    SecurityHeadersFilter secHeaders;

    @Override
    public List<EssentialFilter> getFilters() {

        return Arrays.<EssentialFilter>asList(new EssentialFilter[] { corsFilter.asJava(),secHeaders.asJava(), csrfFilter.asJava()});
                }
}

Also my routes are as follows in conf/routes:

# Map static resources from the /public folder to the /assets URL path
GET     /assets/*file               controllers.Assets.versioned(path="/public", file: Asset)
GET / controllers.HomeController.test()
POST /test controllers.HomeController.testPost()

Removing the @CSRF.formField caused a CSRF unauthorized just as for you.

If you have any obvious differences with your setup I'd be happy to dig further but this seems to not be a direct problem with your code.

0
votes

This might not be applicable to all situation but in my case, the reason was that I was resetting the session in the controller so CSRF token somehow becomes invalid.

If you are calling "withNewSession" in your code and having this error, try removing it and see if the error has gone.