WARNUNG: CSRF-Token-Authentizitätsschienen können nicht überprüft werden

238

Ich sende mit AJAX Daten von der Ansicht an den Controller und habe folgende Fehlermeldung erhalten:

WARNUNG: Die Authentizität des CSRF-Tokens kann nicht überprüft werden

Ich denke, ich muss dieses Token mit Daten senden.

Weiß jemand, wie ich das machen kann?

Edit: Meine Lösung

Dazu habe ich den folgenden Code in den AJAX-Beitrag eingefügt:

headers: {
  'X-Transaction': 'POST Example',
  'X-CSRF-Token': $('meta[name="csrf-token"]').attr('content')
},
kbaccouche
quelle
7
Haben Sie <% = csrf_meta_tag%> in Ihrem Layout-Header?
Anatoly
ja so: <% = csrf_meta_tags%>
kbaccouche
6
Haben Sie JQuery-Rails- Bibliotheken, die clientseitige Ajax- Funktionen bieten?
Anatoly
2
Und die HAML-Methode besteht darin, "= csrf_meta_tags" hinzuzufügen
Ege Akpinar
nette Frage, danke für die Frage
AMIC MING

Antworten:

374

Du solltest das tun:

  1. Stellen Sie sicher, dass Sie <%= csrf_meta_tag %>in Ihrem Layout haben

  2. Fügen Sie beforeSendzu allen Ajax-Anforderungen hinzu, um den Header wie folgt festzulegen:


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

So senden Sie Token in allen Anforderungen, die Sie verwenden können:

$.ajaxSetup({
  headers: {
    'X-CSRF-Token': $('meta[name="csrf-token"]').attr('content')
  }
});
Chau Hong Linh
quelle
5
Vielen Dank! Arbeitete für mich wie ein Zauber!
Mischa Moroshko
35
Die vom Rails-Team bereitgestellte jQuery UJS-Bibliothek fügt das CSRF-Token automatisch zur jQuery AJAX-Anforderung hinzu. Die README-Datei enthält Anweisungen zum Einrichten. github.com/rails/jquery-ujs/blob/master/src/rails.js#L91
James Conroy-Finn
1
Beachten Sie, dass Sie den Header für alle Anforderungen gleichzeitig mit der Funktion $ .ajaxSetup festlegen können.
Pieter Jongsma
1
Ausgezeichnet! Ich habe eine Weile nach dieser Antwort gesucht. Funktioniert nahtlos. Vielen Dank!
Cassi.lup
4
Wenn Sie jQuery UJS wie oben vorgeschlagen verwenden, müssen Sie sicherstellen, dass das Rails-UJS-Include nach dem JQuery -Include kommt. Andernfalls schlägt es mit demselben Fehler wie das Op fehl.
Topher Fangio
31

Der beste Weg, dies zu tun, besteht <%= form_authenticity_token.to_s %>darin, das Token direkt in Ihrem Rails-Code auszudrucken. Sie müssen kein Javascript verwenden, um den Dom nach dem csrf-Token zu durchsuchen, wie in anderen Posts erwähnt. Fügen Sie einfach die Header-Option wie folgt hinzu.

$.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) %>"
})
ADAM
quelle
7
Statt dessen Befehl für jede Ajax tun, die Sie hinzufügen könnte Header zu $ .ajaxSetup () .
Scott McMillin
1
Ich würde eher empfehlen, diese Antwort zu verwenden ...
opsidao
14
Ich mag den Ansatz, ERB im Javascript zu verwenden, nicht wirklich.
Radixhound
Dies zwingt Sie dazu, Ihr Javascript mit ERB zu generieren, was sehr einschränkend ist. Selbst wenn es Orte gibt, an denen ERB gut passt, gibt es andere, an denen dies nicht der Fall ist, und es wäre eine Verschwendung, es nur hinzuzufügen, um den Token zu erhalten.
Sockmonk
22

Wenn ich mich richtig erinnere, müssen Sie Ihrem Formular den folgenden Code hinzufügen, um dieses Problem zu beheben:

<%= token_tag(nil) %>

Vergessen Sie den Parameter nicht.

Auralbee
quelle
8
Eigentlich sollte dies sein : <%= token_tag(nil) %>. Dann erhalten Sie das automatisch generierte Token.
Szeryf
15

In der Tat einfachster Weg. Machen Sie sich nicht die Mühe, die Überschriften zu ändern.

Stell sicher dass du hast:

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

Machen Sie einfach ein verstecktes Eingabefeld wie folgt:

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

Oder wenn Sie einen jQuery Ajax-Beitrag wünschen:

$.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);
    }
});
Walter Schreppers
quelle
Das Hinzufügen des versteckten Eingabefelds zu meinem Eingabeformular löste das Problem für mich.
Teemu Leisti
Dies erfolgt automatisch, wenn Sie die Formular-Helfer von Rails verwenden.
Jason FB
13

Ein Upgrade von einer älteren App auf Rails 3.1, einschließlich des csrf-Meta-Tags, löst es immer noch nicht. Auf dem rubyonrails.org-Blog geben sie einige Upgrade-Tipps, insbesondere diese Abfragezeile, die im Kopfbereich Ihres Layouts enthalten sein sollte:

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

entnommen aus diesem Blog-Beitrag: http://weblog.rubyonrails.org/2011/2/8/csrf-protection-bypass-in-ruby-on-rails .

In meinem Fall wurde die Sitzung bei jeder Ajax-Anforderung zurückgesetzt. Durch Hinzufügen des obigen Codes wurde dieses Problem behoben.

Danny
quelle
10
  1. Stellen Sie sicher, dass Sie <%= csrf_meta_tag %>in Ihrem Layout haben
  2. Fügen Sie ein hinzu beforeSend, um das csrf-Token in die Ajax-Anforderung zum Festlegen des Headers aufzunehmen. Dies ist nur für postAnfragen erforderlich .

Der Code zum Lesen des csrf-Tokens ist im verfügbar rails/jquery-ujs, daher ist es imho am einfachsten, ihn wie folgt zu verwenden:

$.ajax({
  url: url,
  method: 'post',
  beforeSend: $.rails.CSRFProtection,
  data: {
    // ...
  }
})
Nathanvda
quelle
Einfach, ohne erneut zu implementieren, was bereits in Rails enthalten ist. Dies sollte die ausgewählte Antwort sein.
Jiehanzheng
In Rails 5.1 funktioniert auch:headers: { 'X-CSRF-Token': Rails.csrfToken() }
Olhor
@ Nathanvda, Vielleicht können Sie diese ähnliche Frage beantworten: stackoverflow.com/questions/50159847/…
6

Die Antworten mit der höchsten Bewertung sind korrekt, funktionieren jedoch nicht, wenn Sie domänenübergreifende Anforderungen ausführen , da die Sitzung nur verfügbar ist, wenn Sie jQuery ausdrücklich anweisen, das Sitzungscookie zu übergeben. So geht's:

$.ajax({ 
  url: url,
  type: 'POST',
  beforeSend: function(xhr) {
    xhr.setRequestHeader('X-CSRF-Token', $('meta[name="csrf-token"]').attr('content'))
  },
  xhrFields: {
    withCredentials: true
  }
});
Dreadwail
quelle
Darf ich Sie fragen, ob Sie diese sehr ähnliche Frage beantworten können? stackoverflow.com/questions/50159847/…
5

Sie können es global wie unten schreiben.

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

Kaffeeskript:

  $('#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'))
  }
Tschechisch
quelle
5

Hoppla..

Ich habe die folgende Zeile in meiner application.js verpasst

//= require jquery_ujs

Ich habe es ersetzt und es funktioniert ..

======= AKTUALISIERT =========

Nach 5 Jahren bin ich mit dem gleichen Fehler zurück, jetzt habe ich brandneue Rails 5.1.6 und ich habe diesen Beitrag wiedergefunden. Genau wie der Kreislauf des Lebens.

Das Problem war nun: Rails 5.1 entfernte standardmäßig die Unterstützung für jquery und jquery_ujs und fügte hinzu

//= require rails-ujs in application.js

Es macht die folgenden Dinge:

  1. Bestätigungsdialoge für verschiedene Aktionen erzwingen;
  2. Nicht-GET-Anfragen von Hyperlinks stellen;
  3. Formulare oder Hyperlinks dazu bringen, Daten asynchron mit Ajax zu senden;
  4. Die Schaltflächen zum Senden werden beim Senden des Formulars automatisch deaktiviert, um ein Doppelklicken zu verhindern. (von: https://github.com/rails/rails-ujs/tree/master )

Aber warum ist das csrf-Token für eine Ajax-Anfrage nicht enthalten? Wenn jemand dies im Detail weiß, kommentiere mich einfach. Ich weis das zu schätzen.

Wie auch immer, ich habe Folgendes in meine benutzerdefinierte js-Datei eingefügt, damit es funktioniert (Vielen Dank für andere Antworten, die mir helfen, diesen Code zu erreichen):

$( document ).ready(function() {
  $.ajaxSetup({
    headers: {
      'X-CSRF-Token': Rails.csrfToken()
    }
  });
  ----
  ----
});
Abhi
quelle
Das musste ich auch tun. Der Grund dafür ist, dass ich eine React-App erstelle, um eine vorhandene Rails-App langsam zu ersetzen. Da in der vorhandenen App eine Menge Javascript-Rauschen auftritt, habe ich ein anderes Layout erstellt, das auf eine andere Javascript-Datei zugreift, das ich jedoch nicht aufgenommen habe jquery_ujs. Das war der Trick.
Wylliam Judd
1
Ja, manchmal Wenn wir das bei der Überarbeitung verpassen, überarbeiten Sie etwas. Es ist schwer zu finden, was schief läuft. Da wir nichts manuell tun, damit es funktioniert, schließt Rails es automatisch ein. Wir denken es schon da. Vielen Dank für solche sozialen Qn / Ans Sites
Abhi
Vielleicht können Sie diese ähnliche Frage beantworten: stackoverflow.com/questions/50159847/…
4

Wenn Sie jQuery nicht verwenden und für Anforderungen eine Abruf- API verwenden, können Sie Folgendes verwenden, um Folgendes abzurufencsrf-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)
    })
svnm
quelle
Darf ich Sie fragen, ob Sie diese sehr ähnliche Frage beantworten können? stackoverflow.com/questions/50159847/…
4

Verwenden Sie jquery.csrf ( https://github.com/swordray/jquery.csrf ).

  • Schienen 5.1 oder höher

    $ yarn add jquery.csrf
    //= require jquery.csrf
  • Schienen 5.0 oder früher

    source 'https://rails-assets.org' do
      gem 'rails-assets-jquery.csrf'
    end
    //= require jquery.csrf
  • Quellcode

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

Schwertkampf
quelle
Wird es in 5.1 mit Webpack //= require jquery.csrfnicht funktionieren, oder? Stattdessen habe ich die Pack-JS-Datei verwendet import 'jquery.csrf'. Beachten Sie, dass Sie dies nicht mit einem Pack-Tag in Ihre Ansichten aufnehmen müssen.
Damien Justin Šutevski
3

Wenn Sie Javascript mit jQuery verwenden, um das Token in Ihrem Formular zu generieren, funktioniert dies wie folgt:

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

Natürlich müssen Sie das <%= csrf_meta_tag %>in Ihrem Ruby-Layout haben.

Tim Scollick
quelle
2

Für diejenigen unter Ihnen, die eine Nicht-jQuery-Antwort benötigen, können Sie einfach Folgendes hinzufügen:

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

Ein sehr einfaches Beispiel kann hier genannt werden:

xmlhttp.open ("POST", "example.html", true);
xmlhttp.setRequestHeader ('X-CSRF-Token', $ ('meta [name = "csrf-token"]'). attr ('content'));
xmlhttp.send ();
Mek
quelle
6
Verwendet dies nicht jQuery für Selektoren?
Yule
2

Ich hatte tagelang mit diesem Problem zu kämpfen. Jeder GET-Aufruf funktionierte ordnungsgemäß, aber alle PUTs erzeugten den Fehler "CSRF-Token-Authentizität kann nicht überprüft werden". Meine Website funktionierte einwandfrei, bis ich nginx ein SSL-Zertifikat hinzugefügt hatte.

Ich bin schließlich auf diese fehlende Zeile in meinen Nginx-Einstellungen gestoßen:

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

Nach dem Hinzufügen der fehlenden Zeile "proxy_set_header X-Forwarded-Proto https;" werden alle meine CSRF-Token-Fehler beendet.

Hoffentlich hilft das jemand anderem, der auch seinen Kopf gegen eine Wand schlägt. Haha

Hoffmann
quelle
0

Ich benutze Rails 4.2.4 und konnte nicht herausfinden, warum ich Folgendes bekam:

Can't verify CSRF token authenticity

Ich habe im Layout:

<%= csrf_meta_tags %>

In der Steuerung:

protect_from_forgery with: :exception

Beim Aufrufen tcpdump -A -s 999 -i lo port 3000wurde der gesetzte Header angezeigt (obwohl die Header nicht mit gesetzt werden mussten ajaxSetup- dies wurde bereits durchgeführt):

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

Am Ende schlug es fehl, weil ich Cookies ausgeschaltet hatte. CSRF funktioniert nicht ohne aktivierte Cookies. Dies ist eine weitere mögliche Ursache, wenn dieser Fehler auftritt.

Neil Stockbridge
quelle
Es ist sehr hilfreich!
Joehwang