Search code examples
ruby-on-railscsrfcsrf-protection

protect_from_forgery - does order matter?


I have read this post https://nvisium.com/blog/2014/09/10/understanding-protectfromforgery/ and if I understood correctly, by default in Rails 3 if we have a controller that looks like:

class ApplicationController < ActionController:Base
  protect_from_forgery
end

What will end up happening is that (in case of an attacker) the session will be destroyed. That would mean that if we are doing something like checking if the user is authenticated, since there would be no session, it will stop the request.

So, my question is, I believe that this:

class ApplicationController < ActionController:Base
  protect_from_forgery
  before_action :authenticate_user

  private

  def authenticate_user
    raise NotAuthenticated unless session.key?(:user)
  end
end

Is the proper way of doing it, instead of

class ApplicationController < ActionController:Base
  before_action :authenticate_user
  protect_from_forgery

  private

  def authenticate_user
    raise NotAuthenticated unless session.key?(:user)
  end
end

Or in other words, protect_from_forgery should be the first thing that we do in a controller.

Are my assumptions correct, or I am missing something on how the order of operations work in the controller?


Solution

  • The order of those two methods is not important, no.

    The reason has to do with when those methods get executed: those are Class-level methods that are executed in the context of the class itself when Ruby loads the file.

    Look at the source for protect_from_forgery:

    def protect_from_forgery(options = {})
      options = options.reverse_merge(prepend: false)
    
      self.forgery_protection_strategy = protection_method_class(options[:with] || :null_session)
      self.request_forgery_protection_token ||= :authenticity_token
      before_action :verify_authenticity_token, options
      append_after_action :verify_same_origin_request
    end
    

    These are basically macros that add code to your class when they are invoked, a form of metaprogramming. You could replace the method call in the class with setting those things manually and it would be the same.

    This all happens when your code first gets loaded, before the application has booted up.