Thursday, September 15, 2011

Rails 3.1 CSRF token authenticity for JSON Content Type


When designing a REST API for one of my resources, I am getting a warning message like this:

> WARNING: Can't verify CSRF token authenticity


in the logs. This should NOT be happening, as I am accessing my resource using a JSON API through a POST request. The following rails file:

rails/actionpack/lib/action_controller/metal/request_forgery_protection.rb

clearly states

"Only HTML and JavaScript requests are checked, so this will not protect your XML API (presuably you'll have a different authentication scheme there anyway). Also, GET requests are not protected as these should be idempotent."

In addition to this message in the logs, the rails code also "resets" my non-existant session. Doing a little digging shows a problem in this function:

Where there is no check on the content type. By the way, you can easily set the content type of your request in a CURL request like this:
> curl -H "Content-Type: application/json" -d '{"email":abc@xyz.com", "password":"xyzc123"}' http://localhost:3000/sessions.json -i
Comparing the same code to Rails 3.0:


def verified_request?
        !protect_against_forgery? || request.forgery_whitelisted? ||
          form_authenticity_token == params[request_forgery_protection_token]
end
I see the additional check "request.forgery_whitelisted" which ends up checking for "JSON" and "XML" content types and returns true. I plan to submit a bug and in the mean time, you can work around by overriding

in your controller or application controller. Good luck!