【问题标题】:Rails 3 CSRF token still submitsRails 3 CSRF 令牌仍然提交
【发布时间】:2020-07-06 02:21:51
【问题描述】:

我正在使用旧版 Rails 应用程序,我正在尝试清理一些 CSRF 漏洞。如果我从表单中删除隐藏的 CSRF 字段,我仍然可以成功提交表单。

出现问题的唯一迹象是日志中的警告:WARNING: Can't verify CSRF token authenticity

在某些页面,protect_from_forgery 会捕获请求,如果没有 csrf 令牌,应用程序将崩溃,但它的命中和未命中取决于页面:例如。登录页面在没有令牌的情况下工作,但更新用户页面没有。

我尝试为protect_from_forgery 制定一个自定义策略(由Marc Gauthier 建议),类似于:

protect_from_forgery with: :MyStrategy

class MyStrategy
  byebug
  def initialize(controller)
    @contriller = controller
  end

  def handle_unverified_request
    puts "HELLO!"
    Rails.logger.warn [
      "handle_unverified_request",
      "#{@controller.controller_name}-#{@controller.action_name}"
    ].join(" - ")

  end
end

启动应用程序时这似乎没有任何作用,byebug 调用将暂停,但我从未收到 puts 消息或错误日志。

我也尝试了诸如with: :exception 之类的常规策略,但没有任何变化,有些页面可以工作,有些页面不能,但它们是一致的。

【问题讨论】:

  • 我担心你提到的“碰巧”行为。你是说同一个表单在没有 CSRF 令牌的情况下有时会成功提交,有时会失败?似乎不可能!这真的是你说的吗?对不起,但我相信你一定是弄错了。但也许我还没有理解你所说的“碰巧”是什么意思。
  • 同一个表单要么总是工作要么不工作,但是根据页面的不同,CSRF 保护工作或不工作。因此,例如,对于登录页面和忘记密码页面,令牌将不起作用(我可以删除它并毫无问题地提交表单)但是在编辑用户详细信息页面上,如果我删除令牌,表单将不会提交并且应用程序将崩溃(如预期/期望的那样)。
  • 你能再分享一些代码吗?例如。 ApplicationController 的完整代码(大概是您调用 protect_from_forgery 的地方)可能会有所帮助。
  • 不幸的是,作为一个旧版客户端应用程序,ApplicationController 的行数超过 400 行,我不愿意从他们的应用程序中分享这么多内容。有什么我应该寻找的具体内容或您想查看的特定方法吗?我意识到这不是很有帮助,我只是希望有人可能遇到过类似的事情。
  • 专注于登录。控制器是什么,我不知道就叫它LoginController。 LoginController 或 ApplicationController 中有一行无法通过 CSRF 检查。开始删除与接收登录表单无关的所有内容,逐节,逐个方法,同时在每次删除后尝试提交表单。最终,您将删除导致问题的行。没有看到你的代码,这是我能建议的最好的。如果你在调试别人的 400 行 ApplicationController,这可能是最好的方法。

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


【解决方案1】:

通常保护登录用户会话免受 CSRF 影响很重要,因此在许多应用程序中通常禁用登录/注销保护以防止合法用户出错。在大多数情况下,如果会话无论如何都要终止/重置,RF 不会造成太大的伤害。

查找skip_before_action :verify_authenticity_token 禁用正在由protect_from_forgery 安装的操作

检查您的测试方法 - 隐藏的表单字段并不总是必要的,因为 rails 还为 ajax 表单使用 X-CSRF-Token 标头。要正确测试防伪保护 - 进行实际的防伪尝试,例如使用 curl

检查config.action_controller.allow_forgery_protection 是否未针对开发/生产禁用,并且控制器或其祖先没有allow_forgery_protection 重载并为相关请求返回false。不太可能,但应用程序可能有一些其他部分的防伪保护被覆盖,请参阅request_forgery_protection.rb

PS。类上下文中的byebug 对于这种情况不是很有用,更明显的方法是raise "Hello CSRF" in handle_unverified_request

【讨论】:

  • 嘿@Vasfed,感谢您的建议。没有skip_before_action 的实例会禁用protect_from_forgery。我们只有一个声明:config.action_controller.allow_forgery_protection = false 在测试配置中。我目前正在尝试 raise 声明和 curl 请求,但我不确定这是否会有所帮助我不相信这个表单使用任何 ajax。
  • 这并没有完全回答我的问题,但我会给你赏金,因为 curl 建议让我们走上了正轨,而你是赏金周期间唯一发布的答案。跨度>
【解决方案2】:

看起来 Rails 正在做它应该做的事情,只是重置会话,这对于登录表单或忘记密码表单并不重要。因为我们只有protect_from_forgerywith: :exception 直到sometime in Rails 5 才成为默认值)。

有人会认为添加with: :exception 会起作用,但事实并非如此。解决方法是把Exception类的内容提取出来放到application_controller

 def handle_unverified_request
     raise ActionController::InvalidAuthenticityToken
  end

这适用于登录和忘记密码表单,其他表单(正确地不允许错误请求通过)保持不变,这有点奇怪,因为我认为两者都会因InvalidAuthenticityToken raised 而失败。

这当然留下了一个问题,为什么protect_from_forgery with: :exception 不起作用?

【讨论】:

    猜你喜欢
    • 2023-03-23
    • 1970-01-01
    • 2016-07-14
    • 2019-07-28
    • 2017-05-19
    • 2012-12-11
    • 2013-08-01
    • 2016-09-28
    • 2016-12-20
    相关资源
    最近更新 更多