38

I'm currently working on a Rails application with a few other developers, and there are POSTs being made to the server via AJAX through Angular. On occasion, we've noticed a few InvalidAuthenticityToken exceptions come through our email logs, which has led to us wanting to take action.

Since this request is coming through Angular, my belief is that we are treating the server as an API, and we should be using protect_from_forgery with: :null_session. However, protect_from_forgery with: :reset_session seems to provide us with the same resolution.

I don't wish to blindly plug code in just because it's recommended, so I'd like to know the difference between these two forgery protection approaches. When would I use one over the other, and why would I prefer its usage?

Makoto
  • 104,088
  • 27
  • 192
  • 230
  • 2
    The answer provided is a good one, but I would recommend diving into this deeper if you want to make sure you are truly protecting against CSRF attacks. There are some important subtleties that are worth noting. Here are some blog articles that I found helpful to understand the risks when I had questions about this same topic: https://nvisium.com/blog/2014/09/10/understanding-protectfromforgery/ https://blog.srcclr.com/when-rails-protect_from_forgery-fails/ http://www.sitepoint.com/techniques-to-secure-your-website-with-ruby-on-rails-part-1/ The main take-away that I had was that there are ins – aldefouw May 11 '16 at 21:25

2 Answers2

64

Based on my interpretation of the code, it seems that:

  • null_session should be used in API-style controllers, where you have no use for the session object. This sounds like the appropriate solution for your Angular app. The user's preexisting session (i.e. as set by other, traditional controllers) will remain intact. It is also the default behavior if you don't specify a with option to protect_from_forgery.
  • reset_session is for traditional controllers. When the CSRF check fails, it tells Rails to blow away the user's session and continue handling the request. This sounds like a "paranoid mode" where you want to log the user out of your app if there is any evidence of tampering in the request.

If your Rails app doesn't use sessions at all, then these are interchangeable.

However, if you do use sessions in some parts of your app but not others (i.e. a mix of traditional and API controllers), then null_session is probably what you should use. Otherwise, if you use reset_session, an API request made by the browser will cause users to be logged out of their browser session.

ehannes
  • 499
  • 4
  • 18
Matt Brictson
  • 10,904
  • 1
  • 38
  • 43
  • This makes sense. If the scenario were such that this were applied at a higher level; that is, if this was defined in a parent controller class that other controllers inherited, would what you're saying still hold? – Makoto Jul 06 '15 at 00:14
  • 1
    Yes, for example if all your API controllers inherit from an API::BaseController parent class, then you would put `protect_from_forgery with: :null_session` in that base class and it would apply to all controllers that inherit from it. Your non-API controllers would still get the default behavior as defined by `ApplicationController` (`with: :exception`). – Matt Brictson Jul 06 '15 at 00:20
  • Perfect, this is what I was looking for. Thanks for this. – Makoto Jul 06 '15 at 00:21
  • 3
    i believe that `null_session` is the default (not `reset_session` as above), per these docs: http://api.rubyonrails.org/classes/ActionController/RequestForgeryProtection/ClassMethods.html – whatbird Feb 05 '16 at 18:36
  • 1
    @MattBrictson Then how do I mitigate csrf attacks from my API app, if I use `null_session` ? – Arup Rakshit May 25 '19 at 12:42
0

Just want to add a bit of my findings to better understand these 3 strategies. The difference is in what happens after verify_authenticity_token check fails:

  • exception strategy crashes your app
  • reset_session strategy completely deletes user session
  • null_session strategy nullifies the session ONLY during request and the app still continues execution.
who_khiers
  • 101
  • 1
  • 6