Rails 4 真实性令牌
Posted
技术标签:
【中文标题】Rails 4 真实性令牌【英文标题】:Rails 4 Authenticity Token 【发布时间】:2013-04-21 22:54:14 【问题描述】:当我遇到一些真实性令牌问题时,我正在开发一个新的 Rails 4 应用程序(在 Ruby 2.0.0-p0 上)。
在编写响应 json 的控制器时(使用 respond_to
类方法),我遇到了 create
操作,当我尝试使用 curl
创建记录时,我开始收到 ActionController::InvalidAuthenticityToken
异常。
我确定我设置了-H "Content-Type: application/json"
并使用-d "<my data here>"
设置了数据,但仍然没有运气。
我尝试使用 Rails 3.2(在 Ruby 1.9.3 上)编写相同的控制器,但我没有遇到任何真实性令牌问题。我四处搜索,发现 Rails 4 中的真实性令牌发生了一些变化。据我了解,它们不再自动插入表单中了吗?我想这会以某种方式影响非 html 内容类型。
有没有什么办法可以绕过这个问题,而不必请求 HTML 表单,获取真实性令牌,然后使用该令牌发出另一个请求?还是我完全遗漏了一些非常明显的东西?
编辑:我刚刚尝试使用脚手架在新的 Rails 4 应用程序中创建一条新记录,而没有进行任何更改,但我遇到了同样的问题,所以我想这不是我做的。
【问题讨论】:
【参考方案1】:我想我只是想通了。我更改了(新)默认值
protect_from_forgery with: :exception
到
protect_from_forgery with: :null_session
根据ApplicationController
中的评论。
# Prevent CSRF attacks by raising an exception.
# For APIs, you may want to use :null_session instead.
您可以通过查看request_forgery_protecton.rb
的源代码,或者更具体地说,查看以下几行代码来发现区别:
在Rails 3.2:
# This is the method that defines the application behavior when a request is found to be unverified.
# By default, \Rails resets the session when it finds an unverified request.
def handle_unverified_request
reset_session
end
在Rails 4:
def handle_unverified_request
forgery_protection_strategy.new(self).handle_unverified_request
end
哪个会调用the following:
def handle_unverified_request
raise ActionController::InvalidAuthenticityToken
end
【讨论】:
您可以同时删除 :with 选项,默认为 :null_session:api.rubyonrails.org/classes/ActionController/… 有没有办法对非 JSON 调用使用异常,对 JSON 调用(也称为 API 调用)使用空会话? @JamesMcMahon 您可以编写自己的before_action
来检查格式以及请求是否得到验证。我不知道设置条件的任何内置方法。
在 rails 4.1.6 中,我还必须在我的 API 的应用程序控制器上指定 skip_before_action :verify_authenticity_token
才能完成这项工作。
在 Rails 4.2 中,您不必再禁用 :verify_authenticy_token
。它默认为:null_session
,顾名思义,它只是给你一个没有会话的请求。您可以改为通过 API 密钥验证请求。【参考方案2】:
与其关闭csrf保护,不如在表单中加入下面这行代码
<%= tag(:input, :type => "hidden", :name => request_forgery_protection_token.to_s, :value => form_authenticity_token) %>
如果你使用form_for或form_tag来生成表单,那么它会自动在表单中添加上面的代码行
【讨论】:
如果您正在制作表单,这是一个很好的建议,但问题是指使用 JSON 进行 API 调用。 谢谢你,这回答了我在使用车把时手写代码的问题!【参考方案3】:将以下行添加到对我有用的表单中:
<%= hidden_field_tag :authenticity_token, form_authenticity_token %>
【讨论】:
实际上并不适用于 api 调用 就我而言,我使用的是 Rails4。我可以通过单击提交按钮来提交表单。但是如果我通过 JS 代码提交表单,就会出现这个错误。这个答案为我解决了这个问题。 对于我基于 Rails 4.0.8 的应用程序,编写=token_tag nil
或(在 .erb 中)<%= token_tag nil %>
就足够了
您似乎通过将令牌设置为 nil 来禁用身份验证?
这样做安全吗?【参考方案4】:
只要您不专门实现 API,我认为通常关闭 CSRF 保护并不好。
在查看 ActionController 的 Rails 4 API 文档时,我发现您可以在每个控制器或每个方法库上关闭伪造保护。
例如,为您可以使用的方法关闭 CSRF 保护
class FooController < ApplicationController
protect_from_forgery except: :index
【讨论】:
这在 Rails 4 中为我完成了 - 尝试删除后抛出错误。 ^^【参考方案5】:遇到了同样的问题。通过添加到我的控制器来修复它:
skip_before_filter :verify_authenticity_token, if: :json_request?
【讨论】:
未定义方法 `json_request?'对于#<0x000000030a54a8>0x000000030a54a8> 【参考方案6】:你试过了吗?
protect_from_forgery with: :null_session, if: Proc.new |c| c.request.format.json?
【讨论】:
【参考方案7】:这个官方文档 - 讨论如何正确关闭 api 的伪造保护 http://api.rubyonrails.org/classes/ActionController/RequestForgeryProtection.html
【讨论】:
没错,但答案是从 2013 年开始的 - 事情发生了变化。虽然您的官方接受的答案很好 - 我的链接只是提供了对该主题的更好的深入概述【参考方案8】:这是 Rails 中的一项安全功能。在表单中添加这行代码:
<%= hidden_field_tag :authenticity_token, form_authenticity_token %>
文档可以在这里找到: http://api.rubyonrails.org/classes/ActionController/RequestForgeryProtection.html
【讨论】:
【参考方案9】:这些功能是出于安全和防伪目的而添加的。 但是,为了回答您的问题,这里有一些输入。 您可以在控制器名称后添加这些行。
这样,
class NameController < ApplicationController
skip_before_action :verify_authenticity_token
以下是不同版本的导轨的一些行。
Rails 3
skip_before_filter :verify_authenticity_token
Rails 4:
skip_before_action :verify_authenticity_token
如果您打算为所有控制器例程禁用此安全功能,您可以在 application_controller.rb 文件中将 protect_from_forgery 的值更改为 :null_session。
这样,
class ApplicationController < ActionController::Base
protect_from_forgery with: :null_session
end
【讨论】:
【参考方案10】:如果您将 jQuery 与 rails 一起使用,请注意在未验证真实性令牌的情况下允许进入方法。
jquery-ujs 可以为你管理令牌
您应该已经将它作为 jquery-rails gem 的一部分,但您可能需要将其包含在 application.js 中
//= require jquery_ujs
这就是你所需要的——你的 ajax 调用现在应该可以工作了
有关详细信息,请参阅: https://github.com/rails/jquery-ujs
【讨论】:
【参考方案11】:在表单标签中添加authenticity_token: true
【讨论】:
【参考方案12】:当您定义自己的 html 表单时,您必须包含身份验证令牌字符串,出于安全原因,应将其发送到控制器。如果您使用 rails form helper 生成真实性令牌,则会将其添加到表单中,如下所示。
<form accept-charset="UTF-8" action="/login/signin" method="post">
<div style="display:none">
<input name="utf8" type="hidden" value="✓" />
<input name="authenticity_token" type="hidden" value="x37DrAAwyIIb7s+w2+AdoCR8cAJIpQhIetKRrPgG5VA=">
</div>
...
</form>
因此问题的解决方案是添加authentity_token 字段或使用rails form helpers,而不是牺牲安全性等。
【讨论】:
感谢您的回答,尽管这并不能回答最初的问题。该问题询问有关响应 JSON 请求的问题,但您正在为从头开始的 HTML 表单提供解决方案。发出 JSON 请求(想想 API)时,您并没有提交 HTML 表单,而且您可能无法轻松访问真实性令牌。 除非请求的内容实际上是 JSON,在这种情况下您需要将其设置为application/json
。
我知道答案并不完全符合您的要求。但放相关答案的目的是为了帮助用户寻找类似的“真实性问题”。
抱歉我误删了 - “你可以设置 Content-Type: application/x-www-form-urlencoded 上面的解决方案”。【参考方案13】:
我的所有测试都运行良好。但由于某种原因,我将环境变量设置为非测试:
export RAILS_ENV=something_non_test
我忘记取消设置这个变量,因为我开始收到ActionController::InvalidAuthenticityToken
异常。
取消设置$RAILS_ENV
后,我的测试又开始工作了。
【讨论】:
以上是关于Rails 4 真实性令牌的主要内容,如果未能解决你的问题,请参考以下文章