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 中)&lt;%= token_tag nil %&gt; 就足够了 您似乎通过将令牌设置为 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> 【参考方案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="&#x2713;" />
    <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 真实性令牌的主要内容,如果未能解决你的问题,请参考以下文章

Rails 4 真实性令牌 - 在标题和表单隐藏输入中?

即使设置了标头,也无法验证 CSRF 令牌的真实性 Rails 4 Ajax

Rails 3 真实性令牌

Rails 3 AJAX请求真实性令牌被忽略

无法验证 CSRF 令牌的真实性 Rails/React

Rails 3:无法验证 CSRF 令牌的真实性