开发者

How does Rails CSRF protection work?

开发者 https://www.devze.com 2023-02-10 06:57 出处:网络
Rails raises an InvalidAuthenticityToken when the CSRF token doesn\'t match.But, from reading the source, I can\'t figure out how this actually happens.I start by acking the tree for that class:

Rails raises an InvalidAuthenticityToken when the CSRF token doesn't match. But, from reading the source, I can't figure out how this actually happens. I start by acking the tree for that class:

$ ack --ignore-dir=test InvalidAuthenticityToken

actionpack/lib/action_controller/metal/request_forgery_protection.rb
4:  class InvalidAuthenticityToken < ActionControllerError #:nodoc:
17:  # which will check the token and raise an ActionController::InvalidAuthenticityToken

actionpack/lib/action_dispatch/middleware/show_exceptions.rb
22:      'ActionController::InvalidAuthenticityToken' => :unprocessable_entity

Only two hits, ignoring the comment. The first one is the class definition:

class InvalidAuthenticityToken < ActionControllerError #:nodoc:
end

The second one is translating the exception into an HTTP status code. CSRF protection gets enabled by calling protect_from_forgery in the controller, so let's look at that:

def protect_from_forgery(options = {})
  self.request_forgery_protection_token ||= :authenticity_token
  before_filter :verify_authentic开发者_运维问答ity_token, options
end

It adds a filter:

def verify_authenticity_token
  verified_request? || handle_unverified_request
end

Which calls this when verification fails:

def handle_unverified_request
  reset_session
end

So how is InvalidAuthenticityToken actually raised?


The behavior was changed fairly recently but the documentation has yet to be updated. The new approach being used is to presume the session has been hijacked, and therefore to clear the session. Assuming your session contains the all-important authentication information for this request (like the fact you're logged in as alice) and your controller assures the user is authenticated for this action, your request will be redirected to a login page (or however you choose to handle a non logged-in user). However, for requests which are not authenticated, like a sign-up form, the request would go through using an empty session.

It seems this commit also goes on to close a CSRF vulnerability, but I didn't read into the details of that.

To obtain the old behavior, you would simply define this method:

def handle_unverified_request
  raise(ActionController::InvalidAuthenticityToken)
end

You can read more about CSRF and other Rails security issues at the Ruby on Rails Security Guide.


verify_authenticity_token used to be defined as

verified_request? || raise(ActionController::InvalidAuthenticityToken)

but as you noted, it now calls handle_unverified_request, which in turn calls reset_session

I don't think Rails actually throws that exception anymore.

http://weblog.rubyonrails.org/2011/2/8/csrf-protection-bypass-in-ruby-on-rails states

After applying this patch failed CSRF requests will no longer generate HTTP 500 errors, instead the session will be reset. Users can override this behaviour by overriding handle_unverified_request in their own controllers.

https://github.com/rails/rails/commit/66ce3843d32e9f2ac3b1da20067af53019bbb034

0

精彩评论

暂无评论...
验证码 换一张
取 消