Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP

Loading…

CSRF token authenticity Warning for JSON Request #3041

Closed
gshakir opened this Issue · 13 comments

6 participants

@gshakir

When making a JSON Post request I see a warning message:

WARNING: Can't verify CSRF token authenticity

This warning should not happen for JSON post request. I tested with this:

curl -H "Content-Type: application/json" -d '{"email":abc@xyz.com", "password":"xyzc123"}' http://localhost:3000/sessions.json -i

and checking for content type in "verified_request" method fixed it.

@dmathieu
Collaborator

CSRF security happens, whatever the format of the request is.
If you don't want it, you have to remove the call to protect_from_forgery in your ApplicationController.

You can also remove it for one controller, or one action only.

skip_before_filter :verify_authenticity_token, :only => [:index]
@jonleighton
Collaborator

Yeah, this is not a bug. It's supposed to be checked on every non-GET request.

@gshakir

Yes, I agree with what you are saying if the request is an HTML or Ajax request, but this is a REST request so there is no session associated. In the "request_forgery_protection" file it clearly states that CSRF is checked only for browser requests. So I don't want to disable CSRF protection, I want it on for Browser requests and be silent when it is not a browser request. This is how it was in Rails 3.0 when I checked the source.

Actually the bug is nothing but an annoying warning message as my REST request has no state anyway but I am concerned that I will see too many of the warnings and ignore the real thing when it happens. Please clarify if you think otherwise.

@jonleighton
Collaborator

The behaviour changed to fix a security vulnerability in light of new research:

http://weblog.rubyonrails.org/2011/2/8/csrf-protection-bypass-in-ruby-on-rails

@gshakir

Thanks for the clarification. So I have a couple of suggestions to help API developers like me who would like to get rid of the annoying error message (WARNING: Can't verify CSRF token authenticity).

a). Refer this new research URL in the file "request_forgery_protection.rb" and also change the comment in the file that says,

" Only HTML and JavaScript requests are checked,
# so this will not protect your XML API (presumably you'll have a different
# authentication scheme there anyway)."

b). Move the WARN line:

logger.debug "WARNING: Can't verify CSRF token authenticity" if logger

to "handle_unverified_request" so that I can override and check for the content type and take action accordingly.

Again appreciate the clarification.

@jonleighton
Collaborator

Sure, you can improve the documentation in docrails, and you are welcome to submit a patch to change the location of the warning.

@gshakir

Thanks. But I don't know how to do either of them. I will be happy to take a shot if you can point me to some online resources on how to change the documentation and submit a patch.

@dmathieu
Collaborator

There is a guide on rails on how to contribute

@sjmadsen

The more I think about this, I still can't wrap my head around why this change makes sense. Yes, I understand that a browser plug-in could allow an attacker to insert headers and theoretically attack an application. The thing I keep coming back to, though, is that an API shouldn't be using the same authentication mechanism as a browser (presumably session-based sign-in page or HTTP auth). If the authentication path is different, an API request forged from a browser still fails because the API authentication isn't in place.

More importantly, let's assume I'm simply dense and not understanding the problem. What's missing from the explanation of this change and why it is important is advice on how an API client should adapt to it. What's the expectation? Should a client be making an initial GET request to obtain a CSRF token? APIs are usually stateless. Without a session, won't the CSRF token be the same for every API client, forever? If so, nothing has been fixed: an attacker simply adds one more parameter to the forged request and it's still game over.

@dmathieu
Collaborator

If you expect the call to allow external requests without the CSRF authentication, you're expected to explicitely tell your application so with skip_before_filter :verify_authenticity_token.

As it takes a proc, you can even skip the CSRF token on JSON requests only.

That leaves you pretty free to do basically whatever you want to do.

@lisad

CSRFs are a threat when there's a cookie that re-establishes a session. That could be true for either JSON requests or form POSTs. But CSRFs aren't a threat when there's no automatically-sent cookie, or if the server ignores cookies. I don't see "cookie present" as an option for requiring the CSRF token.

What I see happening here is people disabling CSRF protection for JSON because it's getting in the way, making Rails security weaker in practice.

A more subtle architecture would be for Rails to offer to skip CSRF-token-checking, and at the same time drop cookies if present. Perhaps the default setting would be to drop cookies from JSON requests, and to require a CSRF token from HTML requests, but let the server developer change that default at their own responsibility.

@pankajp20

Can any one give me idea on this problem with POST request?

I'm getting same error while updating a record on IE only. This do not happen application wide but occur for specific action of a controller. While submitting a form (action is used to update a record in DB), received error "Can't verify CSRF token authenticity". When checked form in IE, creates hidden field for "authenticity_token" but submitting the form redirect me to root URL of app (in application controller) and gives same error in console. Also form in IE contains "csrf_meta_tags".

I tried to skip validating the CSRF token authenticity for this specific action but then form's data is not submitted (write skip_before_action :verify_authenticity_token, only: [:] in my controller).

This problem is coming after app migrated from Rails 3.2 to 4.2 (Devise version 3.4).

@pankajp20

The problem is resolved, the actual problem was the "div"s. Structure of that page is based on "div" and one "div" (where the form lies) was placed inside table body mistakenly. And that "div" floats in the page causing this bug. Either no table should be used or the "div" should be inside a "td" tag.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Something went wrong with that request. Please try again.