ПОПЕРЕДЖЕННЯ: Неможливо перевірити рейки справжності токена CSRF


238

Я надсилаю дані з виду на контролер з AJAX, і я отримав цю помилку:

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

Думаю, я мушу надсилати цей маркер із даними.

Хтось знає, як я можу це зробити?

Редагувати: Моє рішення

Я зробив це, поставивши наступний код у публікації AJAX:

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

7
у вас в заголовку макета є <% = csrf_meta_tag%> ?
Анатолій

так ось так: <% = csrf_meta_tags%>
kbaccouche

6
у вас є бібліотеки jquery-rails, які забезпечують функціональність на стороні клієнта ajax?
Анатолій

2
І спосіб HAML полягає в тому, щоб додати "= csrf_meta_tags"
Еге Акпінар

приємне запитання, дякую за запитання
AMIC MING

Відповіді:


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
Дякую! Працював для мене як шарм!
Мішко Морошко

35
Бібліотека jQuery UJS, надана командою Rails, автоматично додає маркер CSRF до запиту jQuery AJAX. README містить інструкції щодо налаштування. github.com/rails/jquery-ujs/blob/master/src/rails.js#L91
Джеймс Конрой-Фін

1
Зауважте, що ви можете встановити заголовок для всіх запитів одразу за допомогою функції $ .ajaxSetup.
Пітер Йонгсма

1
Відмінно! Нещодавно шукали цю відповідь. Працює бездоганно. Дякую!
cassi.lup

4
Як зауваження, якщо ви використовуєте jQuery UJS, як було запропоновано вище, вам потрібно переконатися, що включення rails-ujs відбувається після включення jquery або воно вийде з тієї ж помилки, що й op.
Topher Fangio

31

Найкращий спосіб зробити це насправді просто використовувати <%= form_authenticity_token.to_s %>для друку маркера безпосередньо у вашому коді рейлів. Вам не потрібно використовувати javascript для пошуку дому для маркера 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) %>"
})

7
Замість того, щоб робити це для кожної команди ajax, ви можете додати заголовки до $ .ajaxSetup () .
Скотт Макміллін

1
Я скоріше рекомендую скористатися цією відповіддю ...
opsidao

14
Мені не дуже подобається підхід використання ERB в JavaScript.
radixhound

Це змушує вас генерувати ваш JavaScript за допомогою ERB, що дуже обмежує. Навіть якщо є місця, де ERB може бути добре підходить, є й інші, де це не так, і додавання його лише для отримання жетону було б марним.
sockmonk

22

Якщо я добре пам’ятаю, вам потрібно додати наступний код до форми, щоб позбутися цієї проблеми:

<%= token_tag(nil) %>

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


8
На насправді, це повинно бути: <%= token_tag(nil) %>. Потім ви отримуєте автоматично згенерований маркер.
szeryf

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

це робиться автоматично, якщо ви використовуєте помічників форми Rails.
Джейсон ФБ

13

Перехід із старого додатка на рейки 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щоб включити csrf-маркер у запит ajax для встановлення заголовка. Це потрібно лише для postзапитів.

Код для зчитування маркера csrf доступний у програмі rails/jquery-ujs, тому їм найпростіше просто скористатися таким чином:

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

Просто без повторної реалізації того, що вже включено в Rails. Це має бути обрана відповідь.
jiehanzheng

У Rails 5.1 також працює:headers: { 'X-CSRF-Token': Rails.csrfToken() }
1818

@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 років я знову з тією ж помилкою, тепер у мене є абсолютно нові 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 )

Але чому він не включає маркер csrf для запиту ajax? Якщо хтось детально про це знає, просто прокоментуйте мене. Я ціную це.

У будь-якому випадку я додав у власний js-файл наступне, щоб він працював (дякую за інші відповіді, які допомогли мені дійти до цього коду):

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

Це і потрібно було зробити. Причина цього з'явилася в тому, що я будую додаток React, щоб повільно замінити існуючий додаток Rails. Оскільки в наявній програмі спостерігається купа шуму javascript, я створив інший макет, який отримує доступ до іншого файлу javascript, але я не зміг включити його jquery_ujs. Це була хитрість.
Вілліям Джадд

1
Так, Іноді Якщо ми цього не вистачаємо, переробляючи щось, рефактор. Це важко знайти те, що йде не так. Оскільки ми не робимо нічого вручну, щоб він працював, Rails автоматично включав його. Ми думаємо, це вже є. Дякуємо за такі соціальні сайти Qn / Ans
Абхі,

Може бути , ви можете відповісти на це питання: подібний stackoverflow.com/questions/50159847 / ...

4

Якщо ви не використовуєте JQuery і використовувати що - щось на зразок вибірки 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 ).

  • Рейки 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);


У 5.1, використовуючи веб-пакет, //= require jquery.csrfне буде працювати, правда? Замість цього я використав файл js-файлу з import 'jquery.csrf'ним. Зауважте, що вам не потрібно включати це з тегом упаковки у ваші подання.
Дамьєн Джастін Шутевський

3

Якщо ви використовуєте javascript з jQuery для генерації маркера у вашій формі, це працює:

<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 для селекторів?
Юле

2

Я боровся з цим питанням цілими днями. Будь-який дзвінок GET працював правильно, але всі PUT створювали б помилку "Неможливо перевірити справжність маркера 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 вийшли з роботи.

Сподіваємось, це допомагає комусь іншому, який також б'є головою об стіну. ха-ха



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

Врешті-решт це не вдалось, оскільки у мене було вимкнено печиво. CSRF не працює без включення файлів cookie, тому це ще одна можлива причина, якщо ви бачите цю помилку.


це дуже корисно!
joehwang
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.