AngularJS and Rails: CSRF protection

In working through AngularJS and Rails integration, one of the matters that comes up frequently is CSRF protection. This is an important security measure, and this post points to the solution that I found on stackoverflow, and provides the code snippet that I implemented, and how I verified that it seems to be working.  This content has also been included in the Rails 3 and AngularJS tutorial, available from the tutorials menu above, and the Rails 4 and AngularJS tutorial, also available from the tutorial menu above, or this specific post within that tutorial.

There is also a more thorough treatment of this content in another post, here (described in more detail at the bottom of this post).

CSRF protection is aimed at avoiding hacking by cross site scripting.  In turn, cross site scripting is where javascript on one site causes your browser to perform actions on another site (perhaps one that you have credentials on, and are already logged on to).  This is a reasonably esoteric attack that is only likely to be used on high volume web sites (such as facebook and the like), as it relies on someone having built a web site that specifically scripts to target your website.  Unless your website is very high volume, what’s the odds that someone will visit this attack web site and also be logged on to the target website (your website).  Since it’s good practice to implement CSRF protection, since it’s not very hard, and since we plan one day to have a website that dominates the world that everyone wants to use…..we’re implementing this protection.  A good CSRF example (albeit that focuses on Drupal) can be found at epiqo: all your pants are in danger, the wikipedia page also provides good information.

To implement this we’re following the suggestion from stackoverflow: rails csrf protection.  This approach is elegant because all the logic appears to be in the application_controller.rb on the server side, there’s nothing for the angular code to do, and no changes made to each individual controller.  It also looks like it obeys the security requirements to actually prevent cross site scripting, and many people on stack overflow liked it.  I just have a little niggle about whether the cross site scripting might still work – it seems to me that when you send your request with a url in it, that the request will end up with this cookie on it?  However, I think the trick here is that Angular is taking something out of the cookie and putting it into the headers, and only javascript that’s on the site itself can do that – someone external can have your browser automatically send the cookie down, but they can’t take information out of the cookie and move it into the headers.  It’s very elegant.

An alternative approach is through a project that introduces CSRF into rails and angular, ng-rails-csrf.  My feel was that it integrated rails and angular too closely, I wasn’t keen to have my angular living in my rails asset pipeline.

The code that we end up with in application_controller.rb is as follows:

class ApplicationController < ActionController::Base
  protect_from_forgery

  after_filter  :set_csrf_cookie_for_ng

  def set_csrf_cookie_for_ng
    cookies['XSRF-TOKEN'] = form_authenticity_token if protect_against_forgery?
  end

protected

  def verified_request?
    super || form_authenticity_token == request.headers['X_XSRF_TOKEN']
  end  
end

If you’re on rails 4, you the verified_request? line needs hyphens, not underscores:

super || form_authenticity_token == request.headers['X-XSRF-TOKEN']

We can check if this is working in the following way. In our sample app, before this code is implemented, we can go to the club or team entity, and press the delete button.  We’ll see on our rails server console a message WARNING: Can't verify CSRF token authenticity.  In production this transaction would actually reject, in dev and test CSRF protection is turned down to only a warning, as the rspec test cases have difficulty providing the tokens correctly.  Our aim is for this message to go away.

Implement the code snippet into your application_controller, and restart your rails server (I’m not 100% you have to restart, but I think you do).  Then refresh your browser, and look at the network traffic monitor (if you’re on Chrome) to see that the get transaction now sets an XSRF-TOKEN cookie.  Hit the delete button, and you’ll see that your rails server no longer complains about CSRF token authenticity.

Update:

Since I wrote this there have been some extensions.

1.  There is now a gem available that is based on this discussion above https://github.com/jsanders/angular_rails_csrf, provided by jsanders.

2. I’ve written a more elaborate post, dealing with issues relating to Devise, multithreading, and the newer Rails 4 behaviour.

14 thoughts on “AngularJS and Rails: CSRF protection

  1. Pingback: AngularJS and Rails CRUD application using ng-boilerplate and twitter bootstrap: Tutorial Index | technpol

  2. Pingback: Rails app for Angularjs, building the rails league application: part 1 | technpol

  3. Pingback: AngularJS and Rails Tutorial: part 7 form error handling, datepicker | technpol

  4. Pingback: JSON / JSONP XSS vulnerability with AngularJS and Rails | technpol

  5. What about for rails 4? I added the code and the server still replies with “Can’t verify CSRF token authenticity”. Then I tried adding “.config([“$httpProvider”, function(provider) {
    provider.defaults.headers.common[‘X-CSRF-Token’] = $(‘meta[name=csrf-token]’).attr(‘content’);
    }]);” and it still doesn’t work. 😦

  6. Unfortunately I haven’t got to rails 4 yet, so I don’t have a great answer for you. I wasn’t aware that CSRF processing had changed, so I guess I have that to look forward too!!

  7. Pingback: 6: Adding ngGrid and an edit page, and CSRF protection | technpol

  8. Pingback: Rails4, AngularJS, CSRF and Devise | technpol

  9. Great blog you have here but I was wanting to know if you knew of any forums that cover the same topics discussed here?
    I’d really like to be a part of online community where I can get
    comments from other experienced individuals that share the same interest.
    If you have any suggestions, please let me know. Bless you!

  10. Manie: I haven’t really found any as yet. There are some angularJS forums and blogs, and obviously the rails github itself. But I haven’t been particularly active in forums.

Leave a comment