翻译 Rails 5 中每个订单都有自己的 CSRF Token

dothide · 2016年08月05日 · 最后由 gyorou 回复于 2016年08月05日 · 4909 次阅读

这篇博客是我们 《Rails 5 系列文章》 中的一篇。

我们曾 写过一篇博客 介绍什么是 CSRF 以及如何在 Rails 4 中避免 CSRF,建议你读一下那篇文章来更好地理解本文。

嵌套表单可以绕过 Rails 4 提供的 CSRF 保护

一个典型 Rails 4 生成的表单如下:

<form method= "post" action="/money_transfer">
  <input type="hidden" name="authenticity_token" value="token_value">
</form>

黑客使用 JS 代码注入在 Rails 生成表单标签之上嵌套另一个表单。现在它看起像这样:

<form method="post" action="http://www.fraud.com/fraud">
  <form method= "post" action="/money_transfer">
    <input type="hidden" name="authenticity_token" value="token_value">
  </form>
</form>

HTML 规范 不允许使用嵌套表单

由于不允许使用嵌套表单,浏览器将接受最顶层的表单。这样一来就变成了黑客创建的表单。当该表单被提交时,「authenticity_token」也同时被提交,Rails 将做自检然后说一切都正常,这样黑客有可能黑了该网站。

Rails 5 通过为表单生成自定义令牌来修复该问题

在 Rails 5 中,CSRF 能够被加到任意表单中。每个 CSRF token 仅会被其自身所在表单的 method/action 作验证。你可以在控制器中添加以下代码行来增加针对控制器每个表单的 method/action 的真伪令牌。

class UsersController < ApplicationController
  self.per_form_csrf_tokens = true
end

在每个控制器里添加该行代码会感觉繁琐,因此你也可以初始化以下代码,为应用的所有控制器都启用该行为。

# config/application.rb
Rails.configuration.action_controller.per_form_csrf_tokens = true

这将增加针对整个应用每个表单的 method/action 的真伪令牌。之后生成的表单将会如下所示:

<form method= "post" action="/money_transfer">
  <input type="hidden" name="authenticity_token" value="money_transfer_post_action_token">
</form>

这里包含的真伪令牌将仅针对 money_transfer动作和 post 方法。尽管攻击者依然可以在这里拿到 authenticity_token,但攻击将被受限于 money_transfer post 动作。

作者 Prajakta Tambe 于 2016.1.11

被搞糊涂了,攻击者拿了 CSRF token 有啥用处吗?谁来解释一下。

需要 登录 后方可回复, 如果你还没有账号请 注册新账号