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

时间:2011-08-26 10:23:59

标签: ruby-on-rails jquery csrf

我使用AJAX从视图向控制器发送数据,我收到了这个错误:

  

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

我想我必须发送带有数据的令牌。

有谁知道我该怎么做?

编辑:我的解决方案

我是通过将以下代码放在AJAX帖子中来完成的:

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

17 个答案:

答案 0 :(得分:359)

你应该这样做:

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

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


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

答案 1 :(得分:31)

实现此目的的最佳方法实际上是使用<%= 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) %>"
})

答案 2 :(得分:22)

如果我没记错的话,你必须在表单中添加以下代码,以解决这个问题:

<%= token_tag(nil) %>

不要忘记参数。

答案 3 :(得分: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);
    }
});

答案 4 :(得分:13)

从较旧的应用程序升级到rails 3.1,包括csrf元标记仍然没有解决它。在rubyonrails.org博客上,他们提供了一些升级提示,特别是这一行jquery应该放在你的布局的head部分:

$(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请求。添加上面的代码解决了这个问题。

答案 5 :(得分:10)

  1. 确保布局中有<%= csrf_meta_tag %>
  2. 添加beforeSend以在ajax请求中包含csrf-token以设置标头。这仅适用于post次请求。
  3. rails/jquery-ujs中提供了读取csrf-token的代码,因此最简单的方法是使用它,如下所示:

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

答案 6 :(得分:6)

我只是觉得我会在这里链接这篇文章,因为这篇文章有你要找的大部分答案,而且也非常有趣

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

答案 7 :(得分: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
  }
});

答案 8 :(得分: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'))
  }

答案 9 :(得分: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);
    

答案 10 :(得分:4)

oops ..

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

//= require jquery_ujs

我取而代之的是它的工作......

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

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

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

//= require rails-ujs in application.js

它做了以下事情:

  1. 强制执行各种操作的确认对话框;
  2. 从超链接发出非GET请求;
  3. 使表单或超链接与Ajax异步提交数据;
  4. 提交按钮会在表单提交时自动禁用,以防止双击。 (来自:https://github.com/rails/rails-ujs/tree/master
  5. 但为什么不包括ajax请求的csrf令牌?如果有人详细了解这一点,请评论我。我很欣赏。

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

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

答案 11 :(得分:3)

如果您使用javascript和jQuery在表单中生成令牌,则可以使用:

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

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

答案 12 :(得分:3)

如果您没有使用jQuery并使用fetch API之类的请求,则可以使用以下内容获取<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script> <div class="parent"> <div class="div"></div> </div>

csrf-token

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

答案 13 :(得分: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();

答案 14 :(得分:1)

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

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

答案 15 :(得分:1)

我几天来一直在努力解决这个问题。任何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令牌错误都退出了。

希望这可以帮助那些也正在撞墙的人。哈哈

答案 16 :(得分: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将无法正常工作,因此如果您发现此错误,这是另一个可能的原因。