首页 文章

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

提问于
浏览
220

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

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

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

有谁知道我该怎么做?

Edit: My solution

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

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

17 回答

  • 6

    你应该做这个:

    • 确保布局中包含 <%= csrf_meta_tag %>

    • beforeSend 添加到所有ajax请求以设置 Headers ,如下所示:


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

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

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

    <%= token_tag(nil) %>
    

    不要忘记参数 .

  • 31

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

  • 13

    确实最简单的方法 . 不要在改变 Headers 时烦恼 .

    确保你有:

    <%= 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
    • 确保布局中包含 <%= csrf_meta_tag %>

    • 添加 beforeSend 以在ajax请求中包含csrf-token以设置标头 . 只有 post 请求才需要这样做 .

    rails/jquery-ujs 中提供了读取csrf-token的代码,因此最简单的方法是使用它,如下所示:

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

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

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

  • 22

    此处的最高投票答案是正确的,但如果您正在执行 cross-domain 请求将无效,因为除非您明确告诉jQuery传递会话cookie,否则会话将不可用 . 以下是如何做到这一点:

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

    您可以像下面一样全局编写它 .

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

    哎呀..

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

    //= require jquery_ujs
    

    我替换它和它的工作..

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

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

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

    //= require rails-ujs in application.js
    

    它做了以下事情:

    • 强制确认各种动作的对话框;

    • 从超链接发出非GET请求;

    • 使表单或超链接与Ajax异步提交数据;

    • 已提交按钮在表单提交时自动禁用,以防止双击 . (来自:https://github.com/rails/rails-ujs/tree/master

    但为什么不包括ajax请求的csrf令牌?如果有人详细了解这一点,请评论我 . 我很感激 .

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

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

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

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

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

  • 3

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

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

    对于那些需要非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();
    
  • 13

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

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

  • 4

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

  • 0

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

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

相关问题