ATTENZIONE: impossibile verificare i binari di autenticità del token CSRF


238

Sto inviando dati dalla vista al controller con AJAX e ho ricevuto questo errore:

ATTENZIONE: impossibile verificare l'autenticità del token CSRF

Penso di dover inviare questo token con i dati.

Qualcuno sa come posso farlo?

Modifica: la mia soluzione

L'ho fatto inserendo il seguente codice nel post AJAX:

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

7
hai <% = csrf_meta_tag%> nell'intestazione del layout?
Anatoly,

sì in questo modo: <% = csrf_meta_tags%>
kbaccouche

6
hai librerie jquery-rails che forniscono funzionalità lato client Ajax?
Anatoly,

2
E il modo HAML è aggiungere "= csrf_meta_tags"
Ege Akpinar il

bella domanda, grazie per
avermelo

Risposte:


374

Dovresti fare questo:

  1. Assicurati di avere <%= csrf_meta_tag %>nel tuo layout

  2. Aggiungi beforeSenda tutte le richieste Ajax per impostare l'intestazione come di seguito:


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

Per inviare token in tutte le richieste è possibile utilizzare:

$.ajaxSetup({
  headers: {
    'X-CSRF-Token': $('meta[name="csrf-token"]').attr('content')
  }
});

5
Grazie! Ha funzionato per me come un incantesimo!
Misha Moroshko,

35
La libreria jQuery UJS fornita dal team Rails aggiunge automaticamente il token CSRF alla richiesta jQuery AJAX. Il file README contiene istruzioni su come ottenere l'installazione. github.com/rails/jquery-ujs/blob/master/src/rails.js#L91
James Conroy-Finn

1
Nota che puoi impostare l'intestazione per tutte le richieste contemporaneamente con la funzione $ .ajaxSetup.
Pieter Jongsma,

1
Eccellente! Ho cercato per un po 'questa risposta. Funziona perfettamente. Grazie!
cassi.lup,

4
Come nota, se stai usando jQuery UJS come suggerito sopra, devi assicurarti che le rails-ujs include provengano dopo l'inclusione di jquery o falliranno con lo stesso errore dell'op.
Topher Fangio,

31

Il modo migliore per farlo è in realtà solo usare <%= form_authenticity_token.to_s %>per stampare il token direttamente nel codice delle rotaie. Non è necessario utilizzare JavaScript per cercare il token csrf in dom come altri post menzionano. basta aggiungere l'opzione header come di seguito;

$.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
Invece di farlo per ogni comando ajax, puoi aggiungere le intestazioni a $ .ajaxSetup () .
Scott McMillin,

1
Preferirei usare questa risposta ...
opsidao,

14
Non mi piace molto l'approccio dell'utilizzo di ERB nel javascript.
radixhound,

Questo ti costringe a generare il tuo javascript con ERB, il che è molto limitante. Anche se ci sono posti in cui ERB potrebbe essere adatto, ce ne sono altri in cui non lo è, e aggiungerlo solo per ottenere il token sarebbe uno spreco.
sockmonk,

22

Se ricordo bene, devi aggiungere il seguente codice al tuo modulo, per sbarazzarti di questo problema:

<%= token_tag(nil) %>

Non dimenticare il parametro.


8
In realtà, questo dovrebbe essere: <%= token_tag(nil) %>. Quindi ottieni il token generato automaticamente.
szeryf,

15

Il modo davvero più semplice. Non preoccuparti di cambiare le intestazioni.

Assicurati di avere:

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

Basta fare un campo di input nascosto in questo modo:

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

O se vuoi un post ajax jQuery:

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

L'aggiunta del campo di input nascosto al mio modulo di input ha risolto il problema per me.
Teemu Leisti,

questo viene fatto automaticamente se si utilizzano gli helper dei moduli di Rails.
Jason FB,

13

L'aggiornamento da un'app precedente a rails 3.1, incluso il metatag csrf, non lo risolve ancora. Sul blog rubyonrails.org, offrono alcuni suggerimenti per l'aggiornamento, e in particolare questa linea di jquery che dovrebbe andare nella sezione principale del layout:

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

tratto da questo post del blog: http://weblog.rubyonrails.org/2011/2/8/csrf-protection-bypass-in-ruby-on-rails .

Nel mio caso, la sessione veniva reimpostata su ogni richiesta Ajax. L'aggiunta del codice precedente ha risolto il problema.


10
  1. Assicurati di avere <%= csrf_meta_tag %>nel tuo layout
  2. Aggiungi a beforeSendper includere il token csrf nella richiesta ajax per impostare l'intestazione. Questo è richiesto solo per le postrichieste.

Il codice per leggere il token csrf è disponibile in rails/jquery-ujs, quindi è più semplice usarlo, come segue:

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

Semplice senza reimplementare ciò che è già incluso da Rails. Questa dovrebbe essere la risposta selezionata.
jiehanzheng,

In Rails 5.1 funziona anche:headers: { 'X-CSRF-Token': Rails.csrfToken() }
olhor

@nathanvda, Forse si può rispondere a questa domanda simile: stackoverflow.com/questions/50159847/...


6

Le risposte più votate qui sono corrette ma non funzioneranno se si eseguono richieste tra domini poiché la sessione non sarà disponibile se non si dice esplicitamente a jQuery di passare il cookie di sessione. Ecco come farlo:

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

Posso chiederti se puoi rispondere a questa domanda molto simile? stackoverflow.com/questions/50159847/...

5

Puoi scriverlo a livello globale come di seguito.

JS normale:

$(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'))
  }

5

oops ..

Ho perso la seguente riga nel mio application.js

//= require jquery_ujs

L'ho sostituito e funziona ..

======= AGGIORNATO =========

Dopo 5 anni, sono tornato con lo stesso errore, ora ho Rails 5.1.6 nuovo di zecca e ho trovato di nuovo questo post. Proprio come il cerchio della vita.

Ora qual è stato il problema: Rails 5.1 ha rimosso il supporto per jquery e jquery_ujs per impostazione predefinita e aggiunto

//= require rails-ujs in application.js

Fa le seguenti cose:

  1. forzare i dialoghi di conferma per varie azioni;
  2. effettuare richieste non GET da collegamenti ipertestuali;
  3. fare in modo che form o hyperlink invino i dati in modo asincrono con Ajax;
  4. fare in modo che i pulsanti di invio vengano automaticamente disabilitati sull'invio del modulo per impedire il doppio clic. (da: https://github.com/rails/rails-ujs/tree/master )

Ma perché non include il token csrf per la richiesta Ajax? Se qualcuno lo sa in dettaglio, commentami. Lo apprezzo.

Comunque ho aggiunto quanto segue nel mio file js personalizzato per farlo funzionare (Grazie per altre risposte per aiutarmi a raggiungere questo codice):

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

Questo era quello che dovevo fare anch'io. Il motivo per cui è venuto fuori è perché sto creando un'app React per sostituire lentamente un'app Rails esistente. Dato che c'è un sacco di rumore javascript in corso nell'app esistente, ho creato un layout diverso che accede a un diverso file javascript, ma non sono riuscito a includerlo jquery_ujs. Questo era il trucco.
Wylliam Judd,

1
Sì, a volte Se ci manca quando rielaboriamo, rifattorizza qualcosa ... È difficile trovare ciò che non va. Poiché non stiamo facendo nulla manualmente per farlo funzionare, Rails lo include automaticamente. Lo pensiamo già lì. Grazie per tali siti Qn / Ans social
Abhi

Forse si può rispondere a questa domanda simile: stackoverflow.com/questions/50159847/...

4

Se non si utilizza jQuery e si utilizza qualcosa come l' API di recupero per le richieste, è possibile utilizzare quanto segue per ottenere 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)
    })

Posso chiederti se puoi rispondere a questa domanda molto simile? stackoverflow.com/questions/50159847/...

4

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

  • Rotaie 5.1 o successive

    $ yarn add jquery.csrf
    //= require jquery.csrf
  • Rails 5.0 o precedenti

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

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


In 5.1 usando webpack, //= require jquery.csrfnon funzionerà, giusto ?. Invece ho usato il file pack js con import 'jquery.csrf'dentro. Nota che non è necessario includerlo nelle tag con un tag pack.
Damien Justin Šutevski

3

Se stai utilizzando JavaScript con jQuery per generare il token nel tuo modulo, funziona:

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

Ovviamente, devi avere il <%= csrf_meta_tag %>layout di Ruby.


2

Per quelli di voi che hanno bisogno di una risposta non jQuery, è possibile semplicemente aggiungere quanto segue:

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

Un esempio molto semplice può essere qui:

xmlhttp.open ( "POST", "example.html", true);
xmlhttp.setRequestHeader ('X-CSRF-Token', $ ('meta [name = "csrf-token"]'). attr ('content'));
xmlhttp.send ();

6
Questo non utilizza jQuery per i selettori?
Yule,

2

Ho lottato con questo problema per giorni. Qualsiasi chiamata GET funzionava correttamente, ma tutti i PUT generavano un errore "Impossibile verificare l'autenticità del token CSRF". Il mio sito Web funzionava bene fino a quando non avevo aggiunto un certificato SSL a nginx.

Alla fine mi sono imbattuto in questa linea mancante nelle mie impostazioni 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; 
}

Dopo aver aggiunto la riga mancante "proxy_set_header X-Forwarded-Proto https;", tutti gli errori del token CSRF sono stati chiusi.

Spero che questo aiuti qualcun altro che batte anche la testa contro un muro. haha



0

Sto usando Rails 4.2.4 e non sono riuscito a capire perché stavo ottenendo:

Can't verify CSRF token authenticity

Ho nel layout:

<%= csrf_meta_tags %>

Nel controller:

protect_from_forgery with: :exception

Il richiamo tcpdump -A -s 999 -i lo port 3000mostrava l'intestazione impostata (nonostante non fosse necessario impostare le intestazioni con ajaxSetup- era già stato fatto):

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

Alla fine non funzionava perché avevo i cookie disattivati. CSRF non funziona senza i cookie abilitati, quindi questa è un'altra possibile causa se visualizzi questo errore.


è molto utile!
Joehwang,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.