【问题标题】:ActionController::InvalidAuthenticityTokenActionController::InvalidAuthenticityToken
【发布时间】:2011-03-22 19:48:37
【问题描述】:

下面是一个错误,由我的 Rails 应用程序中的表单引起:

Processing UsersController#update (for **ip** at 2010-07-29 10:52:27) [PUT]
  Parameters: {"commit"=>"Update", "action"=>"update", "_method"=>"put", "authenticity_token"=>"ysiDvO5s7qhJQrnlSR2+f8jF1gxdB7T9I2ydxpRlSSk=", **more parameters**}

ActionController::InvalidAuthenticityToken (ActionController::InvalidAuthenticityToken):

每个非get 请求都会发生这种情况,如您所见,authenticity_token 就在那里。

【问题讨论】:

    标签: ruby-on-rails


    【解决方案1】:

    真实性令牌是在您的视图中生成的随机值,用于证明请求是从您网站上的表单提交的,而不是从其他地方提交的。这可以防止 CSRF 攻击:

    http://en.wikipedia.org/wiki/Cross-site_request_forgery

    检查该客户端/IP 是谁,看起来他们正在使用您的网站而没有加载您的视图。

    如果您需要进一步调试,这个问题是一个很好的起点:Understanding the Rails Authenticity Token

    编辑解释: 这意味着他们正在调用该操作来处理您的表单提交,而无需在您的网站上呈现您的表单。这可能是恶意的(例如发布垃圾邮件 cmets),也可能表明客户试图直接使用您的 Web 服务 API。您是唯一一个可以根据您的产品性质和分析您的要求来回答这个问题的人。

    【讨论】:

    • 谢谢,但我已经知道什么是真实性令牌。 检查该客户端/IP 是谁,看起来他们正在使用您的网站但未加载您的视图。 抱歉,“未加载视图”是什么意思?
    • 我的意思是有人(可能是垃圾邮件发送者)可能会在不通过应用程序用户界面的情况下向您的表单提交数据。例如,可以使用 curl 等命令行程序来执行此操作。
    • 约翰完全正确。这意味着他们正在调用该操作来处理您的表单提交,而无需在您的网站上呈现您的表单。这可能是恶意的(例如发布垃圾邮件 cmets),也可能表明客户试图直接使用您的 Web 服务 API。您是唯一可以根据您的产品性质和分析您的要求来回答这个问题的人。
    • 好吧,我误解了温菲尔德的评论。我认为当我使用浏览器时,该应用程序没有以某种方式配置为“加载我的视图”。
    • 我也有另一个想法,这些请求包含一个令牌,但它是无效的。这可能是由于缓存呈现表单的页面或其他可能导致表单陈旧版本的原因造成的。
    【解决方案2】:

    我遇到了同样的问题,但是页面被缓存了。页面使用过时的真实性令牌进行缓冲,并且所有使用 post/put/delete 方法的操作都被视为伪造尝试。错误(422 Unprocessable Entity)被返回给用户。

    Rails 3 的解决方案:
    添加:

     skip_before_filter :verify_authenticity_token  
    

    或如 Rails 4 中指出的“sagivo”添加:

     skip_before_action :verify_authenticity_token
    

    在进行缓存的页面上。

    正如@toobulkeh 所说,这不是:index、:show 操作上的漏洞,但请注意在:put、:post 操作上使用此漏洞。

    例如:

     caches_page :index, :show  
     skip_before_filter :verify_authenticity_token, :only => [:index, :show]
    

    参考:http://api.rubyonrails.org/classes/ActionController/RequestForgeryProtection/ClassMethods.html

    barlop 添加的注释-Rails 4.2 弃用了 skip_before_filter 以支持 skip_before_action https://guides.rubyonrails.org/4_2_release_notes.html“*_filter 系列方法已从文档中删除。不鼓励使用它们以支持 *_action 系列方法”

    对于 Rails 6(正如“collimarco”指出的那样),您可以使用 skip_forgery_protection,并且将其用于不使用会话数据的 REST API 是安全的。

    【讨论】:

    • 不太可能,在您发帖之前我不知道 caches_page。但我会检查 caches_page,谢谢。
    • 在 rails 4 skip_before_action :verify_authenticity_token
    • 这不是漏洞吗?
    • 这不是:index, :show 操作的漏洞。但要小心不要把它放在:put, :post 行动上!
    • 虽然我同意您有时会遇到需要这样做的情况(例如一生中可能只有一次),但您需要意识到您正在通过禁用安全性来修复安全性。不推荐
    【解决方案3】:

    通过从 2.3.8 降级到 2.3.5 解决了问题。 (以及臭名昭著的“您正在被重定向。”问题)

    【讨论】:

    • @Flip 也许是更新接受的答案的想法?
    【解决方案4】:

    对我来说,Rails 4 下这个问题的原因是缺失,

    <%= csrf_meta_tags %>
    

    我的主应用程序布局中的行。我在重写布局时不小心删除了它。

    如果这不在主布局中,您将需要在您想要 CSRF 令牌的任何页面中使用它。

    【讨论】:

    • 我们也收到此错误。但它是中断的。这可能是原因还是不会影响每个错误请求?
    • @Ryan-NealMes,如果您的模板缺少该行,您将收到错误消息。因此,您的某些模板可能有它而其他模板没有。
    • @JamesMcMahon 谢谢,我发现我的情况实际上是由用户清除他们的 cookie 或阻止 cookie 引起的。从这个问题中学到了很多东西!
    【解决方案5】:

    我在 javascript 调用中遇到了这个问题。我只需要将 jquery_ujs 放入 application.js 文件即可解决此问题。

    【讨论】:

    • 是的,没错,我也遇到了这个问题,我在应用程序 js 中添加了 jquery_ujs。它奏效了。
    【解决方案6】:

    我找到了解决办法。

    当您定义自己的 html 表单时,出于安全原因,您可能会忘记包含控制器所需的身份验证令牌字符串。但是,当您使用 Rails 生成器创建表单时,您会得到如下内容:

    <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 表单助手,而不是删除、降级或升级Rails 生成的代码。

    【讨论】:

      【解决方案7】:

      我遇到了这个问题,原因是我将控制器复制并粘贴到了我的应用程序中。我需要将ApplicationController 更改为ApplicationController::Base

      【讨论】:

        【解决方案8】:

        此错误有多种原因(与 Rails 4 相关)。

        1.检查页面布局中的&lt;%= csrf_meta_tags %&gt;

        2。如果使用带有remote: true 选项的form_for 助手,则检查真实性令牌是否与AJAX 调用一起发送。如果不是,您可以在表单块中包含&lt;%= hidden_field_tag :authenticity_token, form_authenticity_token %&gt; 行。

        3。如果请求是从缓存页面发送的,请使用fragment caching 排除发送请求的页面部分,例如button_to 等,否则令牌将过期/无效。

        我不愿意取消 csrf 保护...

        【讨论】:

        • csrf_meta_tags 应该在 中吗?我如何确定它不会与 turbolink 冲突?
        【解决方案9】:

        如果您已完成 rake rails:update 或最近更改了您的 config/initializers/session_store.rb,这可能是浏览器中旧 cookie 的症状。希望这是在开发/测试中完成的(它是为我准备的),并且您可以清除与相关域相关的所有浏览器 cookie。

        如果这是在生产中,并且您更改了 key,请考虑将其更改回使用旧 cookie(

        【讨论】:

        • 是的!对我来说,有一个空的 session_store.rb 会导致错误。
        【解决方案10】:

        安装

        gem 'remotipart' 
        

        可以帮忙

        【讨论】:

        • 虽然这可能是答案,但包含答案的基本部分并解释它为什么/如何工作也很有帮助。
        【解决方案11】:

        我们遇到了同样的问题,但注意到它仅适用于使用 http:// 而不是 https:// 的请求。 session_store 的原因是secure: true:

        Rails.application.config.session_store(
          :cookie_store,
          key: '_foo_session',
          domain: '.example.com',
          secure: true
        )
        

        已通过使用 HTTPS 修复 ~everywhere :)

        【讨论】:

        • 我在使用rails s(非 SSL)而不是我为开发设置的 SSL 端点时遇到了这个问题。直到我读了你的评论,我才意识到我在做什么。一旦我切换回使用 SSL,事情又开始工作了。谢谢!
        • 我在开发中遇到了这个问题。我写的不是secure: true,而是secure: !Rails.env.development?
        【解决方案12】:

        我在本地主机上遇到了同样的问题。我已经更改了应用程序的域,但在 URL 和主机文件中仍然存在旧域。更新了我的浏览器书签和主机文件以使用新域,现在一切正常。

        【讨论】:

          【解决方案13】:

          只需在表单中添加 authenticity_token 即可为我修复它。

          <%= hidden_field_tag :authenticity_token, form_authenticity_token %>
          

          【讨论】:

          • Rails 默认发送令牌。我们不想明确指定它。我觉得在这种情况下令牌会以某种方式发生变化。
          • 但是,如果您在构建表单时不使用助手,则应该手动放置。
          【解决方案14】:

          也许您已经为 HTTPS 设置了 NGINX,但您的证书无效? 我过去也遇到过类似的问题,从 http 重定向到 https 解决了这个问题

          【讨论】:

            【解决方案15】:

            对于 rails 5,最好添加 protect_from_forgery prepend: true 而不是跳过verify_authentication_token

            【讨论】:

            • 为什么?可以加个参考吗?
            【解决方案16】:

            我检查了 是否存在,并且清除浏览器中的 cookie 对我有用。

            【讨论】:

              【解决方案17】:

              ActionController::InvalidAuthenticityToken 也可能是由错误配置的反向代理引起的。如果在堆栈跟踪中出现类似 Request origin does not match request base_url 的行,就会出现这种情况。

              当使用反向代理(例如 nginx)作为 HTTPS 请求的接收者并将未加密的请求传输到后端(例如 Rails 应用程序)时,后端(更具体地说:Rack)需要一些包含更多信息的标头原始客户请求,以便能够应用各种处理任务和安全措施。

              更多详情请点击此处:https://github.com/rails/rails/issues/22965。

              TL;DR:解决方案是添加一些标题:

              upstream myapp {
                server              unix:///path/to/puma.sock;
              }
              
              location / {
                proxy_pass        http://myapp;
                proxy_set_header  Host $host;
                proxy_set_header  X-Forwarded-For $proxy_add_x_forwarded_for;
                proxy_set_header  X-Forwarded-Proto $scheme;
                proxy_set_header  X-Forwarded-Ssl on; # Optional
                proxy_set_header  X-Forwarded-Port $server_port;
                proxy_set_header  X-Forwarded-Host $host;
              }
              

              【讨论】:

              • 哇,我已经搜索了 3 个小时来寻找解决方案,就是这样,谢谢!
              • 非常感谢您在 Rails 方面尝试解决此问题的 6 小时
              • 就我而言,我有一个 proxy_set_header Origin http://$http_host,当我切换到 HTTPS 时,我无法再登录我的网站了。解决方案是使用 proxy_set_header Origin $scheme://$http_host - 这个答案有助于提醒我在日志中查找实际的错误消息。
              • 这发生在我将应用程序从 Rails 5.1 升级到 5.2 后。
              • 我几乎花了 8 个小时,但这个解决方案奏效了。正在使用 rails 6.1,“proxy_set_header X-Forwarded-Ssl on”很重要
              【解决方案18】:

              遵循 Chrome Lighthouse 建议以加快应用程序加载速度,我已异步化我的 Javascript:

              views/layout/application.html.erb

              <%= javascript_include_tag 'application', 'data-turbolinks-track' => 'reload', async: true %>
              

              这破坏了一切,并为我的远程表单获取了令牌错误。删除 async: true 解决了这个问题。

              【讨论】:

                【解决方案19】:

                添加

                //= require rails-ujs 
                

                在

                \app\assets\javascripts\application.js
                

                【讨论】:

                  【解决方案20】:

                  这个答案更具体到 Ruby on Rails,但希望它对某人有所帮助。

                  您需要在每个非 GET 请求中包含 CSRF 令牌。如果您习惯使用 JQuery,Rails 有一个名为 jquery-ujs 的帮助程序库,它建立在它之上并添加了一些隐藏的功能。它所做的一件事是在每个 ajax 请求中自动包含 CSRF 令牌。 See here.

                  如果您像我一样放弃它,您可能会发现自己遇到了错误。您可以手动提交令牌或使用其他库来帮助从 DOM 中抓取令牌。详情请参阅this post。

                  【讨论】:

                    【解决方案21】:

                    在rails 5中,我们需要添加2行代码

                        skip_before_action :verify_authenticity_token
                        protect_from_forgery prepend: true, with: :exception
                    

                    【讨论】:

                      【解决方案22】:

                      对于开发环境,我在 Rails 6 中尝试了许多尝试来解决此问题。但都没有帮助。因此,如果这些建议都不适合您,请尝试以下操作。

                      我找到的唯一解决方案是将一个 txt 文件添加到您的 /tmp 文件夹中。

                      在您应用的根目录中,运行:

                      touch tmp/caching-dev.txt
                      

                      或者在您的 /tmp 文件夹中手动创建一个该名称的文件。由于这为我解决了问题,我认为问题的根源是缓存冲突。

                      【讨论】:

                        【解决方案23】:

                        在我的控制台中运行 rails dev:cache 为我解决了这个问题! (轨道 6)

                        我认为这可能与 Turbolinks 有关,但 CSRF 似乎仅在启用本地缓存时才起作用。

                        【讨论】:

                          【解决方案24】:

                          这发生在我对我的应用程序的注册过程进行手动测试(与多个用户一起注册/登录)时。

                          一个非常简单实用的解决方案可能是按照我的做法,并使用不同的浏览器(如果使用 chrome,则使用隐身浏览器)。

                          在我的情况下,这是一个比禁用安全功能更好的解决方案!

                          【讨论】:

                            【解决方案25】:

                            我从 Rails 4.0 升级到 4.2 时发生了这种情况。

                            verified_request? 的 4.2 实现查看 request.headers['X-CSRF-Token'],而我的 4.0 应用程序获得的标头是 X-XSRF-TOKEN。我的 ApplicationController 中的一个快速修复是添加该功能:

                              def verify_authenticity_token
                                request.headers['X-CSRF-Token'] ||= request.headers['X-XSRF-TOKEN']
                                super
                              end
                            

                            【讨论】:

                              【解决方案26】:

                              我在 Rails 6 中遇到了类似的错误。在尝试了上述解决方案后,我进行了表单审核,发现我在表单中使用了 &lt;button&gt;.....&lt;/button&gt; HTML 标签,而不是通过 Rails 提交

                               表单助手。更改为表单助手解决了该问题。
                                  

                              【讨论】:

                                猜你喜欢
                                • 2018-11-02
                                • 2018-11-27
                                • 2015-11-23
                                • 2014-01-19
                                • 1970-01-01
                                • 2021-12-20
                                • 2017-11-13
                                • 2015-05-21
                                • 2016-11-14
                                相关资源
                                最近更新 更多