“警告:不能验证CSRF令牌真实性”错误 - CORS与Devise和:token_authenticatable [英] "WARNING: Can't verify CSRF token authenticity" error - CORS with Devise and :token_authenticatable

查看:1844
本文介绍了“警告:不能验证CSRF令牌真实性”错误 - CORS与Devise和:token_authenticatable的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个单一页面的应用程式,使用CORS验证其他网域。所有请求都是JSON请求。



我的应用可以验证确定,并可以使GET请求正常。身份验证使用token_authenticatable。也就是说所有请求都附加'?auth_token = whatever'



所以,我的实际问题是,当我尝试做一个PUT请求时,我得到一个警告:在rails日志中验证CSRF令牌真实性消息以及 CanCan :: AccessDenied(您无权访问此页面。)例外。



只需将 skip_before_filter:verify_authenticity_token 添加到rails控制器即可修复此问题。



只是得出结论,我的ajax请求发送一个无效或空的csrf_token。



我真的不明白怎么可能,因为我相信我正确发送X-



基本上,我的应用程序验证,Devise发回auth_token和csrf_token:

  render:status => 200,:json => {
:auth_token => @ user.authentication_token,
:csrf_token => form_authenticity_token
}

然后我将这些标记存储在我的ajax应用程序中,并使用 ajaxSend 在jQuery中设置它,所以jQuery通过每个请求的令牌:

  initialize: - > 
@bindTo $(document),'ajaxSend',@appendTokensToRequest

appendTokensToRequest:(event,jqXHR,options) - >
如果不是@authToken?然后返回

如果@csrfToken?
jqXHR.setRequestHeader'X-CSRF-Token',@csrfToken

如果options.type是'POST'
options.data = options.data +(如果options.data .match(/ \ = /)then'&'else'')+
$ .param auth_token:@authToken
else
options.url = options.url + .url.match(/ \?/)then'&'else'?)+
$ .param auth_token:@authToken

然后,我可以在chrome网络标签中看到,对于每个GET请求,正在发送 auth_token param,以及PUT请求,但是它似乎没有工作,但 X-CSRF-Token 头。





我的理论是CORS正在填充东西。如果您发出CORS请求,您的浏览器实际上会先执行额外 OPTIONS请求,以检查您是否有权访问此资源。



我怀疑是没有通过X-CSRF-Token头的OPTIONS请求,因此rails立即使rails end上的csrf_token无效。然后当jQuery使实际的PUT请求csrf_token它通过不再有效。



这可能是问题吗?



我能做些什么来证明? Chrome似乎不会在网络标签中显示OPTIONS请求,以帮助我调试此问题。



这不是一个主要问题,因为我可以只是把CSRF东西关闭。但我想知道为什么它不工作。

解决方案

我碰到了同样的问题。问题是 _session_id cookie不能在CORS中发送。因此,当Rails试图验证令牌时, session [:_ csrf_token] null ,Rails生成



要解决此问题,您需要在CORS中启用Cookie发送。以下是 Mozilla开发人员网络参考 a>。



客户
- 请参阅您的客户端技术文档。



服务器
- 设置标题 Access-Control-Allow-Credentials 到响应预检(HTTP OPTIONS)调用的 true (string)。


I have a single page app that authenticates to another domain using CORS. All the requests are JSON requests.

My app can authenticates OK and can make GET requests OK. Authentication is using token_authenticatable. I.e. all requests append '?auth_token=whatever'

So, my actual problem is that when I try to do a PUT request I get a WARNING: Can't verify CSRF token authenticity message in the rails log as well as a CanCan::AccessDenied (You are not authorized to access this page.) exception.

Simply adding skip_before_filter :verify_authenticity_token to the rails controller fixes the issue.

Therefore I can only conclude that my ajax requests are sending an invalid or empty csrf_token.

I don't really understand how that can be, since I believe I am correctly sending the X-CSRF-Token header correctly with each ajax request.

Basically, my app authenticates and Devise sends back an auth_token and a csrf_token:

render :status => 200, :json => {
  :auth_token => @user.authentication_token,
  :csrf_token => form_authenticity_token
}

I then store those tokens in my ajax app, and using ajaxSend in jQuery, set it up so jQuery passes those tokens with each request:

initialize: ->
  @bindTo $(document), 'ajaxSend', @appendTokensToRequest

appendTokensToRequest: (event, jqXHR, options) ->
  if not @authToken? then return

  if @csrfToken?
    jqXHR.setRequestHeader 'X-CSRF-Token', @csrfToken

  if options.type is 'POST'
    options.data = options.data + (if options.data.match(/\=/) then '&' else '') +
    $.param auth_token:@authToken
  else
    options.url = options.url + (if options.url.match(/\?/) then '&' else '?') +
    $.param auth_token:@authToken

I can then see in the chrome network tab, that for each GET request the auth_token param is being sent, as well as the X-CSRF-Token header.

On PUT requests however it doesn't seem to be working though.

My theory is that CORS is stuffing things up. If you make a CORS request, your browser actually makes an additional OPTIONS request first just to check that you do have permission to access this resource.

I suspect that it is the OPTIONS request which is not passing the X-CSRF-Token header, thus rails immediately invalidates the csrf_token on the rails end. Then when jQuery makes the actual PUT request the csrf_token it passes is no longer valid.

Could this be the problem?

What can I do to prove that? Chrome doesn't seem to show me the OPTIONS requests in the network tab to help me debug the issue.

It's not a major issue, because I can just turn the CSRF stuff off. But I'd like to know why it's not working.

解决方案

I just ran into the same issue. The problem is that the _session_id cookie cannot be sent in CORS. As a result, when Rails tries to verify the token, the session[:_csrf_token] is null and Rails generates a new one before comparison.

To solve the issue, you need to enable cookie sending in CORS. Here is the Mozilla Developer Network reference. Work is needed on both the server and client side to make it work.

Client - Refer to your client technologies document.

Server - Set the header Access-Control-Allow-Credentials to true (string) in the response to the preflight (HTTP OPTIONS) call.

这篇关于“警告:不能验证CSRF令牌真实性”错误 - CORS与Devise和:token_authenticatable的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆