【问题标题】:Rails ActionController::InvalidCrossOriginRequest on a js requestjs请求上的Rails ActionController::InvalidCrossOriginRequest
【发布时间】:2021-07-11 17:44:50
【问题描述】:

我知道这已经在 SO 上提出a few times,但我无法取得进展。我在 Rails 5.0.7.2 上。

我每天被ActionController::InvalidCrossOriginRequest 抛出数百次。 Rollbar 说它主要是由 Bingbot 引起的,它在我的用户注册模式上,它来自 Devise。是一个GET请求,路径是/users/sign_up

注意:这不是一个表单。它是一个简单询问用户的模式您想如何注册?电子邮件、Fb、Google 身份验证等。

基本上,我的网站上有一些 javascript 操作,例如 reddit 或 stackoverflow upvote 之类的图片。我在这些链接上使用remote: true,而是我有一个$.ajax 调用来处理upvote,如下所示:

var token = document.querySelector('meta[name="csrf-token"]').content;

$.ajax({
  // For the upvote, type will be POST
  type: $this.data('method'),
  beforeSend: function(xhr) {
    xhr.setRequestHeader('X-CSRF-Token', token)
  },
  url: $this.data('url'),
  success: function(data) {
    // Some cleanup...
  }
}); 

一旦登出的访问者尝试投票,它就会触发 ajax 请求,然后暂停(未授权)并重定向,如下所示:

Started POST "/upvotes/toggle_vote"
Processing by UpvotesController#toggle_vote as */*
Completed 401 Unauthorized in 1ms (ActiveRecord: 0.0ms)


Started GET "/users/sign_up"
Processing by RegistrationsController#new as */*

这是我覆盖的设计控制器:

class RegistrationsController < Devise::RegistrationsController

  def new
    # ... other code        

    respond_to do |format|
      format.js   { render layout: false }
      format.html { respond_with self.resource }
    end
  end
end

/views/devise/registrations 内部我有new.js.erb,它打开了“您想如何注册?”模态的。

我的尝试:

  • 我不认为通过添加 protect_from_forgery except: :new 来解决它是正确的答案(正如在类似问题中提出的那样),因为这本质上是不安全的。

  • 我尝试按照this 重新排序respond_to 格式,但这会使注册模式无法打开。

  • 我试图在 respond_to 块中添加一个 format.any { raise ActionController::RoutingError.new("Not Found") } catch-all,但这并没有解决错误。

  • 正如您在上面的 $.ajax 调用中看到的那样,我什至尝试设置 X-CSRF-Token 标头。

顺便说一下,完整的错误文本是这样的:

ActionController::InvalidCrossOriginRequest: Security warning: an embedded &lt;script&gt; tag on another site requested protected JavaScript. If you know what you're doing, go ahead and disable forgery protection on this action to permit cross-origin JavaScript

有什么想法吗?

可能是因为UpvotesController#toggle_vote 重定向到RegistrationsController#new 并从 POST 更改为 GET,所以真实性令牌丢失了吗?

【问题讨论】:

  • 这能回答你的问题吗? Rails InvalidCrossOriginRequest
  • 不幸的是,它没有,因为我认为protect_from_forgery 应该是为了安全起见。该线程中没有其他建议的解决方案。另外,我没有混合 http/https 资源。
  • 怎么样:protect_from_forgery unless: -&gt; { request.format.js? },仅用于您的一些 javascript 操作。
  • 你能分享你的javascript动作代码吗(前端)?还有 - 你使用的是 jquery-rails 还是 rails-ujs?
  • @Joel_Blum 我正在使用 jquery-rails。我稍微整理了一下问题,您现在可以看到我的$.ajax 电话。

标签: javascript ruby-on-rails ruby ajax csrf


【解决方案1】:

您需要使用修改服务器中资源的 ajax 请求发送真实性令牌(post/put/patch/delete)。通常,rails 会将其作为隐藏字段添加到表单中。

【讨论】:

  • 啊,对不起,我编辑了问题以澄清。模态实际上不是一种形式。
  • 不管是不是表单,还是需要提供一个token让rails接受请求。
  • 我的应用程序布局的头部有&lt;%= csrf_meta_tags %&gt;。这不包括吗?
  • 如果您正在执行 ajax (js) 请求,请尝试获取该令牌并将其附加到请求中:const token = document.querySelector('meta[name="csrf-token"]').content
  • 查看我更新的问题。在$.ajax 调用中,我尝试设置真实性令牌。但是现在我在想,既然有重定向和从 POST 到 GET 的切换,它可能不会发送它?这可能吗?
【解决方案2】:

对我来说,这似乎是一个 CORS 问题,就像错误提示我从嵌入式 javascript 发出的 API 调用一样,该调用位于与服务器上定义的域不同的域中。这会触发 CORS 错误。通常要修复 CORS 错误,您需要在允许的域列表中添加带有网站域的标头 Access-Control-Allow-Origin。 您可以使用 rack cors gem 轻松做到这一点:https://github.com/cyu/rack-cors

【讨论】:

    【解决方案3】:

    在表单中添加它应该可以解决问题:

    <% hidden_field_tag :authenticity_token, form_authenticity_token %>
    

    【讨论】:

    • 对不起,我应该指定,模态实际上是不是一种形式。我知道设计路线通常是这样,但在这种情况下,弹出的模式只是询问用户他们希望如何进行。使用电子邮件/facebook/等注册。
    【解决方案4】:

    几个想法:

    1. 你不应该自己放置 csrf 令牌,jquery-railsrails-ujs(我不确定你使用的是哪一个)为你做;使用 rails-ujs 你需要使用Rails.ajax 方法

    2. There is no redirecting POST to GET and keeping the original POST headers ,这意味着您确实在 GET 请求中丢失了 csrf 令牌(但是您通常不会在 GET 请求中发送或需要 CSRF 令牌,因此请检查您为什么这样做)。

    【讨论】:

    • 关于#1,我正在使用 jquery-rails。关于#2,你是对的,这一切都是有道理的。如果您查看我的问题中的日志输出,它来自 Devise 的行为方式。它尝试运行受before_action :authenticate_user! 保护的/upvotes/toggle_vote 操作。那么控制权就交给RegistrationsController#new
    猜你喜欢
    • 2018-03-21
    • 2014-06-06
    • 2015-01-07
    • 2017-08-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-10-11
    相关资源
    最近更新 更多