3

Ruby On Rails 框架包含一些特性,可以轻松构建公开 Web 服务 API 的服务器应用程序。例如,执行以下操作的控制器:

respond_to :html, :json, :xml

def show
  @thing = Thing.find(params[:id])
  respond_with @thing
end

...将处理两个 Web 浏览器的“显示”操作,返回 HTML,并将项目“@thing”呈现为 JSON 或 XML,用于指定此数据格式的请求。

在此特定示例中,基于 GET 的“显示”操作不涉及任何特殊的安全措施。现在考虑与上述类似的情况,但对于诸如“创建”或“更新”之类的操作 - 由(模拟)PUT 或(实际)POST 请求激活的事物。现在 CSRF 保护开始发挥作用。

在这里,遗憾的是,Rails 似乎只设计用于处理来自在同域网页中执行的 JavaScript 代码的“API 调用”(用于非 HTML 格式响应),对于任何可能向 Web 浏览器客户端提供 HTML 内容的控制器,其中CSRF 保护是强制性的。JavaScript 代码可以查找 Rails 包含的神奇“元”标记,读取 CSRF 令牌并将其提交回 XHR 调用,这些调用在服务器上调用基于 POST 的操作或类似操作。

但是外部调用者呢?如果我们有 Rails 支持一个网站,但我们想制作一个与同一个前端通信的原生 iOS 或 Android 应用程序怎么办?该应用程序将进行服务调用——很好,Rails 使这很容易——但是任何修改服务器上数据的尝试都会失败,因为我们没有 CSRF 令牌。我们不能仅仅绕过 CSRF 保护,因为相同的控制器代码处理 Web 浏览器以及“纯 API”客户端。

所有与 Rails 和 API 调用相关的 CSRF 问题的答案似乎都假设您将有不同的控制器来应对这种情况。但这很愚蠢-如果仅对网页中的JavaScript代码有用,那么所有“使您的应用程序易于公开为服务”的意义何在,除非您在绕过CSRF的特殊控制器中复制一堆代码允许非网络客户端?这种额外的控制器只会增加攻击面。

有谁知道推荐的“正确”模式来处理 Rails 应用程序中的 CSRF 保护,这些应用程序具有可能被 Web 浏览器或非 Web 浏览器客户端(如本机 iOS 或 Android 应用程序)“调用”的操作?像“respond_with(...)”这样的内置东西并没有做任何有用的事情,比如总是生成一个 JSON/XML 对象,其中包含 CSRF 令牌作为无所不在的字段。我能想到的最好的就是自己做,例如将“@thing”渲染为:

{
  csrf: "abcdef...7890",
  object: { ...JSON representation of @thing... }
}

......但这似乎有点像一个黑客,相当多的工作,它似乎绕过了世界+狗的CSRF,无论如何都会在每个请求上宣布最新的令牌。必须有更好的方法:-)

4

1 回答 1

0

嗯,医生

打开请求伪造保护。请记住,仅检查非 GET、HTML/JavaScript 请求。

建议 JSON 和 XML 响应的请求已经不会被 csrf 检查,我认为你的目标是什么?它实际上不是那样工作的吗?

您还可以在您的控制器中覆盖 verify_authenticity_token以具有自定义逻辑,用于何时实际执行验证;这是一个非常简单的方法,它调用其他实际的工作方法来进行验证并在未验证的情况下做出响应,因此您可以重写以仅在某些情况下进行验证检查(如果这是您需要的)。或者不要覆盖,只需根据相同的想法编写自己的 before_filter,然后调用自己的 before_filter ——查看源代码,这几乎就是所有内容protect_from_forgery,添加 verify_authenticity_token为 before_filter。不过,将来做这些事情中的任何一个都可能向前兼容,也可能不向前兼容。

啊,我看到你链接到的注释宣布 CSRF 保护发生在“所有非 GET 请求”,所以我猜说它仅适用于 HTML 请求的文档已经过时了——但这让我想,原因是什么为了那个改变?(该公告没有准确记录漏洞的性质,我也没有去寻找差异)。您当然可以以一种或另一种方式成功地取消它,并使 XML/JSON 请求不再检查 CSRF ——但是您是否会重新引入 3.0.4 旨在修补的任何漏洞,这对您的应用程序是否重要?我不知道。

于 2012-08-21T03:53:13.370 回答