Rails CSRF保护如何运作?

时间:2011-02-15 05:51:42

标签: ruby-on-rails ruby ruby-on-rails-3

当CSRF令牌不匹配时,Rails会引发InvalidAuthenticityToken。但是,从阅读source,我无法弄清楚这是如何发生的。我开始为该课程寻找树:

$ 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

只有两次点击,忽略了评论。第一个是类定义:

class InvalidAuthenticityToken < ActionControllerError #:nodoc:
end

第二个是将异常转换为HTTP状态代码。通过调用控制器中的protect_from_forgery来启用CSRF保护,让我们看一下:

def protect_from_forgery(options = {})
  self.request_forgery_protection_token ||= :authenticity_token
  before_filter :verify_authenticity_token, options
end

它添加了一个过滤器:

def verify_authenticity_token
  verified_request? || handle_unverified_request
end

验证失败时会调用此方法:

def handle_unverified_request
  reset_session
end

那么InvalidAuthenticityToken实际上是如何提出的呢?

2 个答案:

答案 0 :(得分:22)

行为是changed fairly recently,但文档尚未更新。使用的新方法是假设会话已被劫持,因此清除会话。假设您的会话包含此请求的所有重要身份验证信息(例如您以alice身份登录的事实),并且您的控制器确保用户已对此操作进行身份验证,您的请求将被重定向到登录页面(或者您选择处理未登录的用户)。但是,对于未经过身份验证的请求(如注册表单),请求将使用空会话。

似乎这个提交还继续关闭CSRF vulnerability,但我没有读到详细信息。

要获得旧行为,您只需定义此方法:

def handle_unverified_request
  raise(ActionController::InvalidAuthenticityToken)
end

您可以在Ruby on Rails Security Guide了解有关CSRF和其他Rails安全问题的更多信息。

答案 1 :(得分:9)

verify_authenticity_token曾被定义为

verified_request? || raise(ActionController::InvalidAuthenticityToken)

但正如您所说,它现在调用handle_unverified_request,然后调用reset_session

我不认为Rails实际上会抛出异常。

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

  

应用此补丁后CSRF失败   请求将不再生成HTTP   500个错误,而不是会话   被重置。用户可以覆盖它   通过覆盖的行为   handle_unverified_request在他们自己   控制器。

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