这篇博客是我们 《Rails 5 系列文章》 中的一篇。
我们曾 写过一篇博客 介绍什么是 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 中,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