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


238

我正在使用AJAX将数据从视图发送到控制器,但出现此错误:

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

我想我必须将此令牌与数据一起发送。

有人知道我该怎么做吗?

编辑:我的解决方案

我是通过将以下代码放入AJAX帖子中来完成此操作的:

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

7
布局标题中是否有<%= csrf_meta_tag%>
阿纳托利(Anatoly)

是这样的:<%= csrf_meta_tags%>
kbaccouche

6
是否有提供ajax客户端功能的jquery-rails库?
阿纳托利,

2
而HAML方式是添加“ = csrf_meta_tags”
Ege

好问题,谢谢提问
AMIC MING 2015年

Answers:


374

你应该做这个:

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

5
谢谢!像魅力一样为我工作!
Misha Moroshko

35
Rails团队提供的jQuery UJS库自动将CSRF令牌添加到jQuery AJAX请求中。自述文件包含有关如何进行设置的说明。github.com/rails/jquery-ujs/blob/master/src/rails.js#L91
James Conroy-Finn

1
请注意,您可以使用$ .ajaxSetup函数一次为所有请求设置标头。
Pieter Jongsma,

1
优秀的!一直在寻找这个答案。无缝工作。谢谢!
cassi.lup 2013年

4
需要注意的是,如果您按照上述建议使用jQuery UJS,则需要确保rails-ujs包含 jquery包含之后,否则它将失败并出现与op相同的错误。
Topher Fangio

31

最好的方法实际上是<%= 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) %>"
})

7
您可以为$ .ajaxSetup()添加标头,而不是为每个ajax命令执行此操作。
Scott McMillin

1
我宁愿建议使用此答案 ...
opsidao 2012年

14
我真的不喜欢在JavaScript中使用ERB的方法。
radixhound

这迫使您使用ERB生成JavaScript,这是非常有限的。即使在某些地方ERB可能很适合,但在其他地方则没有,再加上它只是为了获得代币将是浪费。
sockmonk 2014年

22

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

<%= token_tag(nil) %>

不要忘记参数。


8
实际上,这应该是:<%= token_tag(nil) %>。然后,您将获得自动生成的令牌。
szeryf 2012年

15

确实是最简单的方法。不要为更改标题而烦恼。

确保您具有:

<%= 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);
    }
});

将隐藏的输入字段添加到我的输入表单中为我解决了这个问题。
Teemu Leisti 2014年

如果您使用Rails的表单助手,这将自动完成。
Jason FB

13

从较旧的应用程序升级到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请求后重置的。添加上面的代码解决了该问题。


10
  1. 确保<%= csrf_meta_tag %>布局中有
  2. 添加一个beforeSend以在ajax请求中包含csrf令牌以设置标头。仅对于post请求是必需的。

可以使用读取csrf令牌的代码rails/jquery-ujs,因此恕我直言,使用它最简单,如下所示:

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

无需重新实现Rails已经包含的内容即可轻松完成。这应该是选定的答案。
jiehanzheng'2

在Rails 5.1中也可以使用:headers: { 'X-CSRF-Token': Rails.csrfToken() }
olhor

@nathanvda,也许您可​​以回答这个类似的问题:stackoverflow.com/questions/50159847/…–


6

此处票数最高的答案是正确的,但是如果您执行跨域请求,则该答案将不起作用,因为除非您明确告诉jQuery传递会话cookie,否则该会话将不可用。这样做的方法如下:

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

请问您能否回答这个非常相似的问题?stackoverflow.com/questions/50159847/…–

5

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

普通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'))
  }

5

哎呀..

我错过了我的application.js中的以下行

//= require jquery_ujs

我更换了它,它的工作..

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

5年后,我返回了Same错误,现在有了全新的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()
    }
  });
  ----
  ----
});

这也是我需要做的。出现这个问题的原因是因为我正在构建一个React App来慢慢替换现有的Rails App。由于现有应用程序中存在大量JavaScript杂音,因此我创建了访问其他JavaScript文件的不同布局,但未能包含jquery_ujs。那是诀窍。
Wylliam Judd

1
是的,有时候如果我们在返工时错过了它,请重构某些东西。很难找到出了什么问题。因为我们没有手动做任何事情来使它起作用,所以Rails会自动包含它。我们认为它已经在那里。感谢您提供这样的社交Qn / Ans网站
Abhi

也许你能回答这个类似的问题stackoverflow.com/questions/50159847/...

4

如果您不使用jQuery并使用类似fetch 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)
    })

请问您能否回答这个非常相似的问题?stackoverflow.com/questions/50159847/…–

4

使用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);


在5.1中使用webpack,//= require jquery.csrf行不通,对吧?相反,我在其中使用了pack js文件import 'jquery.csrf'。注意:你必须与你的意见包装标签包括这个。
达米安·贾斯汀·斯捷夫斯基

3

如果您在jQuery中使用javascript来生成表单中的令牌,则可以使用以下方法:

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

显然,您需要<%= csrf_meta_tag %>在Ruby布局中添加。


2

对于确实需要非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();

6
这不使用jQuery作为选择器吗?
Yule 2015年

2

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

希望这可以帮助其他也在墙上撞头的人。哈哈



0

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


非常有用!
joehwang
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.