警告:不能验证CSRF令牌真实性轨道

我用AJAXand发送数据从视图到控制器,我得到了这个错误:

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

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

有人知道我该怎么做吗?

编辑:我的解决方案

我通过在AJAX帖子中放入以下代码来做到这一点:

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

如果我没记错的话,你必须添加以下代码到你的表单,以摆脱这个问题:

<%= token_tag(nil) %>

不要忘记参数。

你应该这样做:

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

  2. 在所有ajax请求中添加beforeSend来设置头部,如下所示:


$.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')
}
});

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

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

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

$.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) %>"
})

从一个旧的应用程序升级到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请求时都被重置。添加上面的代码解决了这个问题。

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

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

显然,你需要在Ruby布局中有<%= csrf_meta_tag %>

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

也检查控制器解决方案在这个应用程序

确实是最简单的方法。不要费心更改头文件。

确保你有:

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

只需要像这样做一个隐藏的输入字段:

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

或者如果你想要一个jQuery ajax的帖子:

$.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);
}
});

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

xmlhttp.setRequestHeader('X-CSRF-Token', $('meta[name="csrf-token"]').attr('content'));

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

xmlhttp.open("POST","example.html",true);
xmlhttp.setRequestHeader('X-CSRF-Token', $('meta[name="csrf-token"]').attr('content'));
xmlhttp.send();

哎呀. .

我在我的application.js中漏掉了下面一行

//= require jquery_ujs

我把它换了,它还在工作。

=======更新=========

5年后,我回来了同样的错误,现在我有全新的Rails 5.1.6,我又找到了这篇文章。就像生命的循环。

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

//= require rails-ujs in application.js

它做以下事情:

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

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

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

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

您可以像下面这样全局地编写它。

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传递会话cookie,否则会话将不可用。下面是如何做到这一点:

$.ajax({
url: url,
type: 'POST',
beforeSend: function(xhr) {
xhr.setRequestHeader('X-CSRF-Token', $('meta[name="csrf-token"]').attr('content'))
},
xhrFields: {
withCredentials: true
}
});
  1. 确保你的布局中有<%= csrf_meta_tag %>
  2. 添加beforeSend来在ajax请求中包含csrf-token来设置头部。这只对post请求是必需的。

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

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

我使用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将无法工作,因此如果您看到此错误,这是另一个可能的原因。

如果你没有使用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)
})

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

  • Rails 5.1或更高版本

    $ yarn add jquery.csrf
    
    //= require jquery.csrf
    
  • Rails 5.0 or before

    source 'https://rails-assets.org' do
    gem 'rails-assets-jquery.csrf'
    end
    
    //= require jquery.csrf
    
  • Source code

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

    < / p >

我为这个问题纠结了好几天。任何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令牌错误都退出了。

希望这能帮助那些也在用头撞墙的人。哈哈