security safe to disable csrf tokens for json rail

2019-03-28 12:57发布

问题:

I have an existing rails backend website which makes json calls to server. Now,I am developing a mobile iOS app to use the same backend and send calls in json. However, mobile requests are failing with:

WARNING: Can't verify CSRF token authenticity

Searching around stackoverflow, many suggested to disable csrf checks for json calls by using something like this:

# Or this in your application_controller.rb
def verified_request?
  if request.content_type == "application/json"
    true
  else
    super()
  end
end

But my question is , I dont understand how does this prevent csrf attacks in json format? Attacker can always send a json request to our endpoint from their site. Anyone has insights into this? I couldn't find any clear answer to this.

回答1:

What you are describing is very easy to exploit using Flash:

        var request:URLRequest = new URLRequest("http://stackoverflow.com"); 
        request.requestHeaders.push(new URLRequestHeader('Content-Type', 'application/json'));      
        request.data = unescape('{"a":1,"b":{"c":3}}');
        request.method = URLRequestMethod.POST;
        navigateToURL(request, '_blank');   

If you look at the CSRF prevention cheat sheet you can check the referer to make sure its from a domain you trust. If the referer is blank then it could be originating from a https url, so that should be considered a failure. Relying on Ruby's CSRF token is a stronger form a CSRF protection.



回答2:

This is a fix for ajax

Get csrf_token from rails or if using something else, from meta

// js file
var csrf_token = $('meta[name=csrf-token]').attr('content');

or

//js.erb file
var csrf_token = "<%= request.session["<%= _csrf_token %>"] %>";

then add this to js

$("body").bind("ajaxSend", function(elm, xhr, s){
   if (s.type == "POST") {
    // place lines mentioned above here
    // line goes here...
    xhr.setRequestHeader('X-CSRF-Token', csrf_token);
   }
});


回答3:

One approach you can take is to leave on CSRF checks but disable based on a http header being present. If your json requests have a JWT token, you can do something like this in the relevant controllers.

protect_from_forgery with: :exception, unless: -> { some_auth_token.valid? }

Form submissions won't be able to set a http header and thus csrf will protect against it.

You json requests should have an Authorization header to be secure.