Предупреждение: не удается проверить подлинность маркера CSRF rails


Я посылаю данные из представления в контроллер с Ајахи я получил эту ошибку:

предупреждение: не удается проверить подлинность токена CSRF

Я думаю, что я должен отправить этот маркер с данными.

кто-нибудь знает как я могу это сделать ?

редактировать: мое решение

Я сделал это, поместив следующий код в AJAX-ответа:

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

17 ответов:

вы должны сделать это:

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

лучший способ, чтобы сделать это на самом деле просто использовать <%= 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) %>"
})

Если я правильно помню, вы должны добавить следующий код в вашу форму, чтобы избавиться от этой проблемы:

<%= token_tag(nil) %>

Не забудьте параметр.

Ugrading из старого приложения в 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. Добавление выше код решил эту проблему.

действительно самый простой способ. Не беспокойтесь об изменении заголовков.

убедитесь, что у вас есть:

<%= 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);
    }
});
  1. убедитесь, что у вас есть <%= csrf_meta_tag %> в формате
  2. добавить beforeSend чтобы включить csrf-токен в запрос ajax для установки заголовка. Это требуется только для post запросы.

код для чтения csrf-токена доступен в rails/jquery-ujs, так что имхо проще всего просто использовать это, следующим образом:

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

Я просто подумал, что свяжу это здесь, поскольку в статье есть большая часть ответа, который вы ищете, и это также очень интересно

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

лучшие проголосовали ответы здесь правильные, но не будет работать, если вы выполняете кросс-домен запросы, потому что сеанс не будет доступен, если вы явно не скажете jQuery передать cookie сеанса. Вот как это сделать:

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

вы можете написать его глобально, как показано ниже.

нормальный 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'))
  }

упс..

я пропустил следующую строку в моем приложении.js

//= require jquery_ujs

Я заменил его и его рабочих..

======= обновлено =========

после 5 лет, я вернулся с той же ошибкой, теперь у меня есть новый рельсы 5.1.6, и я снова нашел этот пост. Так же, как Круг жизни.

Теперь в чем была проблема: рельсы 5.1 удалена поддержка jquery и jquery_ujs по умолчанию, и добавил

//= require rails-ujs in application.js

Он делает следующие вещи:

  1. диалоги подтверждения силы для различных действий;
  2. сделать не получить запросы от гиперссылок;
  3. сделать формы или гиперссылки отправлять данные асинхронно с Ajax;
  4. кнопки отправки автоматически отключаются при отправке формы, чтобы предотвратить двойной щелчок. (от: https://github.com/rails/rails-ujs/tree/master)

но почему он не включает токен csrf для запроса ajax? Если кто-нибудь знает об этом подробно в комментарии мне. Я ценю это.

В любом случае я добавил следующее в свой пользовательский js-файл, чтобы заставить его работать (Спасибо за другие ответы, которые помогут мне достичь этого кода):

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

Если вы используете javascript с jQuery для создания токена в своей форме, это работает:

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

очевидно, вам нужно иметь <%= csrf_meta_tag %> в вашем макете Ruby.

Если вы не используете 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)
    })

используйте jquery.csrf (https://github.com/swordray/jquery.csrf).

  • рельсы 5.1 или более поздней

    $ yarn add jquery.csrf
    
    //= require jquery.csrf
    
  • рельсы 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);
    

для тех из вас, кто нуждается в ответе не 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();

Если кому-то нужна помощь, связанная с Uploadify и Rails 3.2 (например, когда я гуглил этот пост), этот пример приложения может быть полезен: https://github.com/n0ne/Uploadify-Carrierwave-Rails-3.2.3/blob/master/app/views/pictures/index.html.erb

также проверьте решение контроллера в этом приложении

Я использую рельсы 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

в конце концов это не удалось, потому что у меня были куки выключены. CSRF не работает без включения cookies, так что это еще одна возможная причина если вы видите эту ошибку.

Я боролся с этой проблемой несколько дней. Любой вызов GET работал правильно, но все PUTs генерировали бы ошибку "не удается проверить подлинность токена CSRF". Мой сайт работал нормально, пока я не добавил сертификат SSL в nginx.

Я, наконец, наткнулся на эту недостающую строку в моих настройках 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 завершаются.

надеюсь, это поможет кому-то еще, кто также бьется головой о стену. хаха