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

发布于 2024-12-01 16:22:26 字数 347 浏览 3 评论 0 原文

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

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

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

有谁知道我该怎么做?

编辑:我的解决方案

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

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

I am sending data from view to controller with AJAXand I got this error:

WARNING: Can't verify CSRF token authenticity

I think I have to send this token with data.

Does anyone know how can I do this ?

Edit: My solution

I did this by putting the following code inside the AJAX post:

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(19

放赐 2024-12-08 16:22:26

您应该执行以下操作:

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

You should do this:

  1. Make sure that you have <%= csrf_meta_tag %> in your layout

  2. Add beforeSend to all the ajax request to set the header like below:


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

To send token in all requests you can use:

$.ajaxSetup({
  headers: {
    'X-CSRF-Token': $('meta[name="csrf-token"]').attr('content')
  }
});
腻橙味 2024-12-08 16:22:26

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

The best way to do this is actually just use <%= form_authenticity_token.to_s %> to print out the token directly in your rails code. You dont need to use javascript to search the dom for the csrf token as other posts mention. just add the headers option as below;

$.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) %>"
})
小情绪 2024-12-08 16:22:26

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

<%= token_tag(nil) %>

不要忘记参数。

If I remember correctly, you have to add the following code to your form, to get rid of this problem:

<%= token_tag(nil) %>

Don't forget the parameter.

じее 2024-12-08 16:22:26

确实是最简单的方法。不必费心更改标题。

确保你有:

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

Indeed simplest way. Don't bother with changing the headers.

Make sure you have:

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

Just do a hidden input field like so:

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

Or if you want a 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);
    }
});
明月夜 2024-12-08 16:22:26

从较旧的应用程序升级到 Rails 3.1(包括 csrf 元标记)仍然无法解决问题。在 ruby​​onrails.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 请求时都会重置会话。添加上面的代码解决了这个问题。

Ugrading from an older app to rails 3.1, including the csrf meta tag is still not solving it. On the rubyonrails.org blog, they give some upgrade tips, and specifically this line of jquery which should go in the head section of your layout:

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

taken from this blog post: http://weblog.rubyonrails.org/2011/2/8/csrf-protection-bypass-in-ruby-on-rails.

In my case, the session was being reset upon each ajax request. Adding the above code solved that issue.

月隐月明月朦胧 2024-12-08 16:22:26
  1. 确保布局中有 <%= csrf_meta_tag %>
  2. 添加 beforeSend 以在 ajax 请求中包含 csrf-token 以设置标头。这仅对于 post 请求是必需的。

读取 csrf-token 的代码可以在 rails/jquery-ujs 中找到,所以恕我直言,使用它是最简单的,如下所示:

$.ajax({
  url: url,
  method: 'post',
  beforeSend: $.rails.CSRFProtection,
  data: {
    // ...
  }
})
  1. Make sure that you have <%= csrf_meta_tag %> in your layout
  2. Add a beforeSend to include the csrf-token in the ajax request to set the header. This is only required for post requests.

The code to read the csrf-token is available in the rails/jquery-ujs, so imho it is easiest to just use that, as follows:

$.ajax({
  url: url,
  method: 'post',
  beforeSend: $.rails.CSRFProtection,
  data: {
    // ...
  }
})
蛮可爱 2024-12-08 16:22:26

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

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

The top voted answers here are correct but will not work if you are performing cross-domain requests because the session will not be available unless you explicitly tell jQuery to pass the session cookie. Here's how to do that:

$.ajax({ 
  url: url,
  type: 'POST',
  beforeSend: function(xhr) {
    xhr.setRequestHeader('X-CSRF-Token', $('meta[name="csrf-token"]').attr('content'))
  },
  xhrFields: {
    withCredentials: true
  }
});
神爱温柔 2024-12-08 16:22:26

我只是想将其链接到此处,因为这篇文章包含您正在寻找的大部分答案,而且也非常有趣

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

I just thought I'd link this here as the article has most of the answer you're looking for and it's also very interesting

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

谎言月老 2024-12-08 16:22:26

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

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

You can write it globally like below.

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

Coffee Script:

  $('#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'))
  }
皇甫轩 2024-12-08 16:22:26

如果您不使用 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)
    })

If you are not using jQuery and using something like fetch API for requests you can use the following to get the 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)
    })
情愿 2024-12-08 16:22:26

哎呀..

我在 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. 在表单提交时自动禁用提交按钮以防止双击。
    (来自: https://github.com/rails/rails-ujs/tree/master

但是为什么它不包含ajax请求的csrf令牌呢?如果有人详细了解这一点,请评论我。我很欣赏这一点。

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

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

oops..

I missed the following line in my application.js

//= require jquery_ujs

I replaced it and its working..

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

After 5 years, I am back with Same error, now I have brand new Rails 5.1.6, and I found this post again. Just like circle of life.

Now what was the issue is:
Rails 5.1 removed support for jquery and jquery_ujs by default, and added

//= require rails-ujs in application.js

It does the following things:

  1. force confirmation dialogs for various actions;
  2. make non-GET requests from hyperlinks;
  3. make forms or hyperlinks submit data asynchronously with Ajax;
  4. have submit buttons become automatically disabled on form submit to prevent double-clicking.
    (from: https://github.com/rails/rails-ujs/tree/master)

But why is it not including the csrf token for ajax request? If anyone know about this in detail just comment me. I appreciate that.

Anyway I added the following in my custom js file to make it work (Thanks for other answers to help me reach this code):

$( document ).ready(function() {
  $.ajaxSetup({
    headers: {
      'X-CSRF-Token': Rails.csrfToken()
    }
  });
  ----
  ----
});
肥爪爪 2024-12-08 16:22:26

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

  • Rails 5.1 或更高版本

    $ 纱线添加 jquery.csrf
    
    //= 需要 jquery.csrf
    
  • Rails 5.0 或更低版本

    源 'https://rails-assets.org' 执行
      gem 'rails-assets-jquery.csrf'
    结尾
    
    //= 需要 jquery.csrf
    
  • 源代码

    <前><代码>(函数($) {
    $(文档).ajaxSend(函数(e, xhr, 选项) {
    var token = $('meta[name="csrf-token"]').attr('content');
    if (token) xhr.setRequestHeader('X-CSRF-Token', token);
    });
    })(jQuery);

Use jquery.csrf (https://github.com/swordray/jquery.csrf).

  • Rails 5.1 or later

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

是你 2024-12-08 16:22:26

如果您使用 javascript 和 jQuery 在表单中生成令牌,则此方法有效:

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

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

If you're using javascript with jQuery to generate the token in your form, this works:

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

Obviously, you need to have the <%= csrf_meta_tag %> in your Ruby layout.

北笙凉宸 2024-12-08 16:22:26

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

希望这可以帮助其他同样在墙上碰头的人。哈哈

I struggled with this issue for days. Any GET call was working correctly, but all PUTs would generate a "Can't verify CSRF token authenticity" error. My website was working fine until I had added a SSL cert to nginx.

I finally stumbled on this missing line in my nginx settings:

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

After adding the missing line "proxy_set_header X-Forwarded-Proto https;", all my CSRF token errors quit.

Hopefully this helps someone else who also is beating their head against a wall. haha

卖梦商人 2024-12-08 16:22:26

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

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

if someone needs help related with Uploadify and Rails 3.2 (like me when I googled this post), this sample app may be helpful:
https://github.com/n0ne/Uploadify-Carrierwave-Rails-3.2.3/blob/master/app/views/pictures/index.html.erb

also check the controller solution in this app

近箐 2024-12-08 16:22:26

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

For those of you that do need a non jQuery answer you can simple add the following:

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

A very simple example can be sen here:

xmlhttp.open("POST","example.html",true);
xmlhttp.setRequestHeader('X-CSRF-Token', $('meta[name="csrf-token"]').attr('content'));
xmlhttp.send();
很糊涂小朋友 2024-12-08 16:22:26

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

I'm using Rails 4.2.4 and couldn't work out why I was getting:

Can't verify CSRF token authenticity

I have in the layout:

<%= csrf_meta_tags %>

In the controller:

protect_from_forgery with: :exception

Invoking tcpdump -A -s 999 -i lo port 3000 was showing the header being set ( despite not needing to set the headers with ajaxSetup - it was done already):

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

In the end it was failing because I had cookies switched off. CSRF doesn't work without cookies being enabled, so this is another possible cause if you're seeing this error.

终止放荡 2024-12-08 16:22:26

2023 年升级到 Rails 7 后,由于某种原因我遇到了这个问题。也许我正在使用普通的 jQuery,而不是 jQuery 的某些 Rails 变体,或者任何“UJS”。

通过将其添加到我的页面特定的 Javascript 代码中来修复它:(

    // Add the CSRF token to all ajax requests                                                                                                                      
    $.ajaxSetup({                                                                                                                                                   
      headers: {                                                                                                                                                    
        'X-CSRF-Token': $('meta[name="csrf-token"]').attr('content')                                                                                                
      }                                                                                                                                                             
    });                                                                                                                                                             

我的 html 布局顶部已经有 <%= csrf_meta_tags %>

我正常的 jQuery Ajax 代码如下所示:

      var jqxhr = $.post( "something/example", { color: 'red' })
        .done(function(data) {
          console.log( "Ajax success:");
          console.log( data );
        })
        .fail(function(data) {
          console.log( "Ajax error:");
          console.log( data );
        })
        .always(function() {
          console.log( "Ajax finished" );
        });

After upgrading to Rails 7 in 2023, I had this issue for some reason. Perhaps I'm using normal jQuery instead of some rails variant of jQuery, or whatever "UJS" is.

Fixed it by adding this to my page-specific Javascript code:

    // Add the CSRF token to all ajax requests                                                                                                                      
    $.ajaxSetup({                                                                                                                                                   
      headers: {                                                                                                                                                    
        'X-CSRF-Token': $('meta[name="csrf-token"]').attr('content')                                                                                                
      }                                                                                                                                                             
    });                                                                                                                                                             

(I already had <%= csrf_meta_tags %> at the top of my html layout)

My normal jQuery Ajax code looks like:

      var jqxhr = $.post( "something/example", { color: 'red' })
        .done(function(data) {
          console.log( "Ajax success:");
          console.log( data );
        })
        .fail(function(data) {
          console.log( "Ajax error:");
          console.log( data );
        })
        .always(function() {
          console.log( "Ajax finished" );
        });

童话里做英雄 2024-12-08 16:22:26

进行 API 调用时缺少 CSRF 令牌。您可以在标头中发送“X-CSRF-Token”。
[name=""csrf-token""] 是可以获取令牌的 html 元素。

CSRF token is missing while making API call. You can send ""X-CSRF-Token"" in the headers.
[name=""csrf-token""] is the html element where you can get the token.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文