【问题标题】:How does Rails CSRF protection work?Rails CSRF 保护如何工作?
【发布时间】:2011-06-27 09:15:06
【问题描述】:

当 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 状态代码。 CSRF 保护通过在控制器中调用 protect_from_forgery 来启用,所以让我们看一下:

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到底是怎么升的?

【问题讨论】:

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


    【解决方案1】:

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

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

    要获得旧的行为,您只需定义这个方法:

    def handle_unverified_request
      raise(ActionController::InvalidAuthenticityToken)
    end
    

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

    【讨论】:

    • 谢谢!这就是我运行 3.0.3 但阅读 master 的源代码所得到的。很好地解释了这一变化背后的原因——它甚至比官方博客文章中的更好。
    【解决方案2】:

    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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2010-12-22
      • 2019-11-02
      • 1970-01-01
      • 2019-05-16
      • 2012-07-23
      • 2014-07-31
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多