Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to make sure Rails API is secured from CSRF?

I've been developing Rails app with REST API for access from mobile application.

It works quite well. When user logs in from mobile application, he gets auth_token that he uses in his future requests to API. The issue is that API is also accessible from web by going to path /api/v1/... and because of this, it has to be protected from CSRF.

I have BaseApiController class which inherits from ApplicationController that has protect_from_forgery "enabled". Here's example:

class Api::V1::BaseApiController < ApplicationController
  # ...
end

class ApplicationController < ActionController::Base
  protect_from_forgery
  # ...
end

Now, when I do non-GET requests to my API, with auth_token, my request gets completed successfully, but in the logs I can see the famous WARNING: Can't verify CSRF token authenticity. If I remove protect_from_forgery from my BaseApiController, I don't get any warnings (obviously), but then my API is vulnerable to CSRF attacks (I made a simple HTML form that successfully changes the data across domains when there's no protect_from_forgery).

My question is: How to assure my API stays secure, but also remove the warning when doing non-GET requests?

Here's one of the solutions I've come up with, but it looks more like a hack and executes one extra DB query:

class Api::V1::BaseApiController < ApplicationController
  # ...
  def verified_request?
    super || User.where(authentication_token: params['auth_token']).count > 0
  end
end

More details about the project: Rails 3.2.14, Devise, AngularJS. The project's source code can be found here.

like image 257
Viktor Avatar asked Aug 22 '13 11:08

Viktor


1 Answers

You may see people suggest that CSRF is not an issue for API requests (there is no state to begin with, so what is there to hijack anyhow?), so some suggest the following to simply eliminate the warning:

skip_before_filter :verify_authenticity_token, :only => [:your_method]

However, there was some commentary that it is possible to commit CSRF with text/plain using various Flash and Java-based methods. I believe that was the reason for the security patch in rails a while back: http://weblog.rubyonrails.org/2011/2/8/csrf-protection-bypass-in-ruby-on-rails/

In any event, a good solution that actually checks for an authenticity token can be found here: WARNING: Can't verify CSRF token authenticity rails

It involves actually setting the header in your request.

Good luck!

like image 118
Tyler Avatar answered Sep 21 '22 04:09

Tyler