Rails CSRF保护如何工作?

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

 $ ack --ignore-dir=test InvalidAuthenticityToken actionpack/lib/action_controller/metal/request_forgery_protection.rb 4: class InvalidAuthenticityToken  :unprocessable_entity 

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

 class InvalidAuthenticityToken < ActionControllerError #:nodoc: end 

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

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

它添加了一个filter:

 def verify_authenticity_token verified_request? || handle_unverified_request end 

validation失败时会调用此函数:

 def handle_unverified_request reset_session end 

那么InvalidAuthenticityToken实际上是如何引发的呢?

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

似乎这个提交还继续关闭CSRF漏洞 ,但我没有详细说明。

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

 def handle_unverified_request raise(ActionController::InvalidAuthenticityToken) end 

您可以在Ruby on Rails安全指南中阅读有关CSRF和其他Rails安全问题的更多信息。

verify_authenticity_token曾被定义为

 verified_request? || raise(ActionController::InvalidAuthenticityToken) 

但正如您所指出的,它现在调用handle_unverified_request ,而handle_unverified_request又调用reset_session

我不认为Rails实际上会抛出那个exception。

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

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

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