我知道这在SO上已经提过几次了,但我无法取得进展。我在Rails 5.0.7.2上。
我每天都会被抛出数百次ActionController::InvalidCrossOriginRequest
。Rollbar说这主要是由Bingbot引起的,它在我的用户注册模式中,来自Devise。这是一个GET请求,路径为/users/sign_up
。
注意:这不是一个表单。这是一个模式,它只是询问用户您希望如何注册?电子邮件、Fb、谷歌认证等
基本上,我的网站上有一些javascript操作,比如reddit或stackoverflow upvote。我不是在这些链接上使用remote: true
,而是我有一个$.ajax
调用,它处理向上投票,如下所示:
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 */*
这是我覆盖的Devise控制器:
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
在CCD_ 5内部我有CCD_;你想怎么报名"情态动词
我尝试了什么:
我不认为通过添加
protect_from_forgery except: :new
来解决它是正确的答案(就像在类似的问题中提出的那样(,因为这本质上是不安全的。我尝试根据这个重新排序
respond_to
格式,但这使得注册模式无法打开。我试图在
respond_to
块中加入format.any { raise ActionController::RoutingError.new("Not Found") }
catch-all,但这并没有修复错误。正如您在上面的
$.ajax
调用中看到的,我甚至尝试设置X-CSRF-Token
标头。
顺便说一句,完整的错误文本是:
ActionController::InvalidCrossOriginRequest: Security warning: an embedded <script> 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,所以真实性令牌丢失了吗?
几个想法:
-
你不应该自己放csrf令牌,jquery rails或rails uj(我不确定你用的是哪一个(都会为你做这件事;对于轨道uj,您需要使用
Rails.ajax
方法 -
没有将POST重定向到GET并保留原始POST头,这意味着您确实在GET请求中丢失了csrf令牌(但是,您通常不会在GET请求发送或需要csrf令牌,所以请检查您为什么要这样做(。
您需要发送一个真实性令牌,其中包含修改服务器中资源的ajax请求(post/put/patch/delete(。通常,rails会为您添加它作为表单中的隐藏字段。
将其添加到表单中就可以了:
<% hidden_field_tag :authenticity_token, form_authenticity_token %>
对我来说,这似乎是一个CORS问题,就像错误表明我对嵌入的javascript进行了API调用,该javascript位于与服务器上定义的域不同的域中。这会触发CORS错误。通常要修复CORS错误,您需要在允许的域列表中添加一个标题Access Control Allow Origin和网站的域。您可以使用rack-cors-gem轻松做到这一点:https://github.com/cyu/rack-cors
在Rails5中,我发现
config.action_view.embed_authenticity_token_in_remote_forms = true
避免了同域远程调用的CORS问题,但在Rail 6中似乎没有效果。