警告:无法验证 CSRF 令牌真实性轨道



我正在发送数据从视图到控制器与ajax和我得到这个错误:

警告:无法验证CSRF令牌的真实性

我想我必须发送这个令牌与数据。

有谁知道我该怎么做吗?

编辑:My solution

我将以下代码放入AJAX post中:

headers: {
  'X-Transaction': 'POST Example',
  'X-CSRF-Token': $('meta[name="csrf-token"]').attr('content')
},

你应该这样做:

  1. 确保你的布局中有<%= csrf_meta_tag %>

  2. beforeSend添加到所有ajax请求中,以设置标题如下:


$.ajax({ url: 'YOUR URL HERE',
  type: 'POST',
  beforeSend: function(xhr) {xhr.setRequestHeader('X-CSRF-Token', $('meta[name="csrf-token"]').attr('content'))},
  data: 'someData=' + someData,
  success: function(response) {
    $('#someDiv').html(response);
  }
});

要在所有请求中发送令牌,可以使用:

$.ajaxSetup({
  headers: {
    'X-CSRF-Token': $('meta[name="csrf-token"]').attr('content')
  }
});

最好的方法实际上是使用<%= form_authenticity_token.to_s %>直接在rails代码中打印出令牌。你不需要像其他文章提到的那样使用javascript在dom中搜索csrf令牌。只需添加headers选项,如下所示;

$.ajax({
  type: 'post',
  data: $(this).sortable('serialize'),
  headers: {
    'X-CSRF-Token': '<%= form_authenticity_token.to_s %>'
  },
  complete: function(request){},
  url: "<%= sort_widget_images_path(@widget) %>"
})

如果我没记错的话,您必须将以下代码添加到表单中,以摆脱此问题:

<%= token_tag(nil) %>

不要忘记参数。

确实是最简单的方法。不要费心去改变标题。

确保你有:

<%= csrf_meta_tag %> in your layouts/application.html.erb

就像这样做一个隐藏的输入字段:

<input name="authenticity_token" 
               type="hidden" 
               value="<%= form_authenticity_token %>"/>

或者如果你想要jQuery ajax post:

$.ajax({     
    type: 'POST',
    url: "<%= someregistration_path %>",
    data: { "firstname": "text_data_1", "last_name": "text_data2", "authenticity_token": "<%= form_authenticity_token %>" },                                                                                  
    error: function( xhr ){ 
      alert("ERROR ON SUBMIT");
    },
    success: function( data ){ 
      //data response can contain what we want here...
      console.log("SUCCESS, data="+data);
    }
});

从旧的应用程序升级到rails 3.1,包括csrf元标签仍然不能解决这个问题。在rubyonrails.org博客上,他们给出了一些升级技巧,特别是这一行jquery,它应该放在你的布局的头部部分:

$(document).ajaxSend(function(e, xhr, options) {
 var token = $("meta[name='csrf-token']").attr("content");
  xhr.setRequestHeader("X-CSRF-Token", token);
});

摘自本博客:http://weblog.rubyonrails.org/2011/2/8/csrf-protection-bypass-in-ruby-on-rails.

在我的例子中,每次ajax请求都会重置会话。添加上面的代码解决了这个问题。

  1. 确保你的布局有<%= csrf_meta_tag %>
  2. 添加一个beforeSend,在ajax请求中包含csv -令牌来设置报头。这只需要post请求。

读取csrf-令牌的代码在rails/jquery-ujs中可用,所以我认为使用它是最简单的,如下所示:

$.ajax({
  url: url,
  method: 'post',
  beforeSend: $.rails.CSRFProtection,
  data: {
    // ...
  }
})

这里投票最多的答案是正确的,但如果你正在执行跨域请求将不起作用,因为会话将不可用,除非你显式地告诉jQuery传递会话cookie。方法如下:

$.ajax({ 
  url: url,
  type: 'POST',
  beforeSend: function(xhr) {
    xhr.setRequestHeader('X-CSRF-Token', $('meta[name="csrf-token"]').attr('content'))
  },
  xhrFields: {
    withCredentials: true
  }
});

我只是想把这篇文章链接到这里,因为这篇文章有你想要的大部分答案,而且它也非常有趣

http://www.kalzumeus.com/2011/11/17/i-saw-an-extremely-subtle-bug-today-and-i-just-have-to-tell-someone/

您可以像下面这样全局书写

正常JS:

$(function(){
    $('#loader').hide()
    $(document).ajaxStart(function() {
        $('#loader').show();
    })
    $(document).ajaxError(function() {
        alert("Something went wrong...")
        $('#loader').hide();
    })
    $(document).ajaxStop(function() {
        $('#loader').hide();
    });
    $.ajaxSetup({
        beforeSend: function(xhr) {xhr.setRequestHeader('X-CSRF-Token', $('meta[name="csrf-token"]').attr('content'))}
    });
});
咖啡脚本:

  $('#loader').hide()
  $(document).ajaxStart ->
    $('#loader').show()
  $(document).ajaxError ->
    alert("Something went wrong...")
    $('#loader').hide()
  $(document).ajaxStop ->
    $('#loader').hide()
  $.ajaxSetup {
    beforeSend: (xhr) ->
      xhr.setRequestHeader('X-CSRF-Token', $('meta[name="csrf-token"]').attr('content'))
  }

如果你不使用jQuery和使用的东西,如获取API的请求,你可以使用以下csrf-token:

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

fetch('/users', {
  method: 'POST',
  headers: {
    'Accept': 'application/json',
    'Content-Type': 'application/json',
    'X-CSRF-Token': document.querySelector('meta[name="csrf-token"]').getAttribute('content')},
    credentials: 'same-origin',
    body: JSON.stringify( { id: 1, name: 'some user' } )
    })
    .then(function(data) {
      console.log('request succeeded with JSON response', data)
    }).catch(function(error) {
      console.log('request failed', error)
    })

哎呀…

我错过了application.js

中的以下行
//= require jquery_ujs

我换了它,它还能工作。

======= UPDATED =========

5年后,我又出现了同样的错误,现在我有了全新的Rails 5.1.6,我又发现了这篇文章。就像生命的轮回。

问题是:Rails 5.1默认删除了对jqueryjquery_ujs的支持,并添加了

//= require rails-ujs in application.js

它做以下事情:

  1. 强制各种动作的确认对话框;
  2. 从超链接发出非get请求;
  3. 使表单或超链接使用Ajax异步提交数据;
  4. 在表单提交时自动禁用提交按钮,以防止双击。(来自:https://github.com/rails/rails-ujs/tree/master)

但是为什么它不包括ajax请求的csrf令牌?如果有人知道这个细节,请给我留言。我很感激。

无论如何,我在我的自定义js文件中添加了以下内容以使其工作(感谢其他答案来帮助我达到此代码):

$( document ).ready(function() {
  $.ajaxSetup({
    headers: {
      'X-CSRF-Token': Rails.csrfToken()
    }
  });
  ----
  ----
});

使用jquery。csrf (https://github.com/swordray/jquery.csrf) .

  • Rails 5.1或更高版本

    $ yarn add jquery.csrf
    
    //= require jquery.csrf
    
  • Rails 5.0或之前版本

    source 'https://rails-assets.org' do
      gem 'rails-assets-jquery.csrf'
    end
    
    //= require jquery.csrf
    
  • 源代码
    (function($) {
      $(document).ajaxSend(function(e, xhr, options) {
        var token = $('meta[name="csrf-token"]').attr('content');
        if (token) xhr.setRequestHeader('X-CSRF-Token', token);
      });
    })(jQuery);
    

如果您正在使用javascript和jQuery在表单中生成令牌,这是有效的:

<input name="authenticity_token" 
       type="hidden" 
       value="<%= $('meta[name=csrf-token]').attr('content') %>" />

显然,您需要在Ruby布局中使用<%= csrf_meta_tag %>

我为这个问题挣扎了好几天。任何GET调用都能正常工作,但所有put都会生成"无法验证CSRF令牌真实性"错误。我的网站工作得很好,直到我给nginx添加了SSL证书。

我终于在我的nginx设置中发现了这行缺失的内容:

location @puma { 
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 
    proxy_set_header Host $http_host; 
    proxy_redirect off;
    proxy_set_header X-Forwarded-Proto https;   # Needed to avoid 'WARNING: Can't verify CSRF token authenticity'
    proxy_pass http://puma; 
}

在添加了缺失的行"proxy_set_header X-Forwarded-Proto https;"之后,我所有的CSRF令牌错误都退出了。

希望这能帮助那些也在碰壁的人。哈哈

对于那些确实需要一个非jQuery答案的人,您可以简单地添加以下内容:

<>之前xmlhttp。setRequestHeader (X-CSRF-Token, $('元(name = " csrf-token "]) .attr("内容"));之前

这里有一个非常简单的例子:

<>之前xmlhttp.open("文章"、"html"显示,true);xmlhttp。setRequestHeader (X-CSRF-Token, $('元(name = " csrf-token "]) .attr("内容"));xmlhttp.send ();

如果有人需要与Uploadify和Rails 3.2相关的帮助(就像我在谷歌上搜索这篇文章时一样),这个示例应用程序可能会有所帮助:https://github.com/n0ne/Uploadify-Carrierwave-Rails-3.2.3/blob/master/app/views/pictures/index.html.erb

还检查此应用程序中的控制器解决方案

我使用的是Rails 4.2.4,无法解决为什么我得到:

Can't verify CSRF token authenticity

我有一个布局:

<%= csrf_meta_tags %>

在控制器中:

protect_from_forgery with: :exception

调用tcpdump -A -s 999 -i lo port 3000显示正在设置的标头(尽管不需要使用ajaxSetup设置标头-它已经完成了):

X-CSRF-Token: XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
Content-Type: application/x-www-form-urlencoded; charset=UTF-8
X-Requested-With: XMLHttpRequest
DNT: 1
Content-Length: 125
authenticity_token=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

最后它失败了,因为我把cookie关掉了。如果没有启用cookie, CSRF将无法工作,因此如果您看到此错误,这是另一个可能的原因。

最新更新