security safe to disable csrf tokens for json rails calls?
Asked Answered
R

3

8

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.

Rachellerachis answered 20/5, 2012 at 18:28 Comment(0)
T
2

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.

Telecommunication answered 20/5, 2012 at 22:19 Comment(8)
Thanks Rook. Yes its possible to crack json calls in csrf. Looking at that page gives me more insights into who we can solve that. But do you know how can I use the CSRF tokens generated by Rails so that a mobile app can use them and send the request?Rachellerachis
@Rachellerachis You could bootstrap it, maybe have a static get call that always returns the token.Telecommunication
"you can check the referer to make sure its from a domain you trust." Of course, these can easily be fakedStrontia
@Strontia Although it is trivial to spoof YOUR OWN referer, it is impossible to do so in a CSRF attack. Please read the CSRF Prevention Cheat Sheet, which is linked above.Telecommunication
If you have an API which returns the token, what stops the attacker calling that API to get the token and then passing it to the other API?Dinse
@Trejkaz the same origin policyTelecommunication
@Rook So... wouldn't that stop them sending the JSON too? I don't see how one request is special.Dinse
@Trejkaz The Same origin policy prevents an attacker from reading any HTTP response from another domain, which protects the CSRF synchronization token. If you would like to learn more about CSRF, please read the OWASP page on the attack, additionally the OWASP - CSRF prevention cheat sheet contains more methods of using the same origin policy to prevent CSRF. If you do not understand the SoP, read the 'browser security handbook' distributed by Google.Telecommunication
D
1

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);
   }
});
Disclaimer answered 6/6, 2012 at 9:6 Comment(2)
The JS example could be a bad one because you're going to precompile your assets and that won't be dynamically regenerated. Just a tip. That one could be really scary because it would work in development, but not in production.Partridgeberry
@Partridgeberry thanks for your comment :-) I've added a comment to the last block of code instructing the user where to place the lines mentioned above. This should survive asset pre-compilation, agree?Disclaimer
L
0

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.

Lakesha answered 2/3, 2019 at 21:3 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.