【问题标题】:Rails 4 Authenticity TokenRails 4 真实性令牌
【发布时间】: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 应用程序中创建一条新记录,而没有进行任何更改,但我遇到了同样的问题,所以我想这不是我做的。

【问题讨论】:

    标签: ruby-on-rails ruby ruby-on-rails-4 authenticity-token


    【解决方案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 后,我的测试又开始工作了。

              【讨论】:

                猜你喜欢
                • 2011-03-04
                • 2014-07-04
                • 1970-01-01
                • 1970-01-01
                • 2011-02-11
                • 1970-01-01
                • 1970-01-01
                • 2012-07-29
                • 2013-07-22
                相关资源
                最近更新 更多