AVERTISSEMENT: impossible de vérifier les rails d'authenticité du jeton CSRF


238

J'envoie des données de la vue au contrôleur avec AJAX et j'ai eu cette erreur:

AVERTISSEMENT: impossible de vérifier l'authenticité du jeton CSRF

Je pense que je dois envoyer ce jeton avec des données.

Est-ce que quelqu'un sait comment faire cela?

Edit: Ma solution

J'ai fait cela en mettant le code suivant dans le message AJAX:

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

7
avez-vous <% = csrf_meta_tag%> dans votre en-tête de mise en page?
Anatoly

oui comme ceci: <% = csrf_meta_tags%>
kbaccouche

6
avez-vous des bibliothèques jquery-rails qui fournissent des fonctionnalités côté client ajax?
Anatoly

2
Et la façon HAML est d'ajouter "= csrf_meta_tags"
Ege Akpinar

belle question, merci d'avoir posé la question
AMIC MING

Réponses:


374

Vous devriez faire ceci:

  1. Assurez-vous que vous avez <%= csrf_meta_tag %>dans votre mise en page

  2. Ajoutez beforeSendà toutes les requêtes ajax pour définir l'en-tête comme ci-dessous:


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

Pour envoyer un jeton dans toutes les demandes, vous pouvez utiliser:

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

5
Merci! A fonctionné pour moi comme un charme!
Misha Moroshko

35
La bibliothèque jQuery UJS fournie par l'équipe Rails ajoute automatiquement le jeton CSRF à la demande jQuery AJAX. Le fichier README contient des instructions sur la configuration. github.com/rails/jquery-ujs/blob/master/src/rails.js#L91
James Conroy-Finn

1
Notez que vous pouvez définir l'en-tête pour toutes les demandes à la fois avec la fonction $ .ajaxSetup.
Pieter Jongsma

1
Excellent! Cherche depuis un certain temps pour cette réponse. Fonctionne parfaitement. Merci!
cassi.lup

4
Notez que si vous utilisez jQuery UJS comme suggéré ci-dessus, vous devez vous assurer que l'inclusion de rails-ujs vient après l'inclusion de jquery ou il échouera avec la même erreur que l'op.
Topher Fangio

31

La meilleure façon de le faire est en fait simplement d'utiliser <%= form_authenticity_token.to_s %>pour imprimer le jeton directement dans votre code de rails. Vous n'avez pas besoin d'utiliser javascript pour rechercher le token csrf dans le dom comme d'autres articles le mentionnent. ajoutez simplement l'option en-têtes comme ci-dessous;

$.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
Au lieu de faire cela pour chaque commande ajax, vous pouvez ajouter des en- têtes à $ .ajaxSetup () .
Scott McMillin

1
Je recommanderais plutôt d'utiliser cette réponse ...
opsidao

14
Je n'aime pas vraiment l'approche de l'utilisation d'ERB dans le javascript.
radixhound

Cela vous oblige à générer votre javascript avec ERB, ce qui est très limitant. Même s'il y a des endroits où ERB pourrait être un bon choix, il y en a d'autres où il ne l'est pas, et l'ajouter juste pour obtenir le jeton serait un gaspillage.
sockmonk

22

Si je me souviens bien, vous devez ajouter le code suivant à votre formulaire, pour vous débarrasser de ce problème:

<%= token_tag(nil) %>

N'oubliez pas le paramètre.


8
En fait, cela devrait être: <%= token_tag(nil) %>. Ensuite, vous obtenez le jeton généré automatiquement.
szeryf

15

En effet le moyen le plus simple. Ne vous embêtez pas à changer les en-têtes.

Assurez-vous que vous avez:

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

Faites simplement un champ de saisie caché comme ceci:

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

Ou si vous voulez un article 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);
    }
});

L'ajout du champ de saisie masqué à mon formulaire de saisie a résolu le problème pour moi.
Teemu Leisti

cela se fait automatiquement si vous utilisez les assistants de formulaire de Rails.
Jason FB

13

La mise à niveau d'une ancienne application vers rails 3.1, y compris la balise Meta csrf ne le résout toujours pas. Sur le blog rubyonrails.org, ils donnent quelques conseils de mise à niveau, et en particulier cette ligne de jquery qui devrait aller dans la section tête de votre mise en page:

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

extrait de cet article de blog: http://weblog.rubyonrails.org/2011/2/8/csrf-protection-bypass-in-ruby-on-rails .

Dans mon cas, la session était réinitialisée à chaque demande ajax. L'ajout du code ci-dessus a résolu ce problème.


10
  1. Assurez-vous que vous avez <%= csrf_meta_tag %>dans votre mise en page
  2. Ajoutez un beforeSendpour inclure le jeton csrf dans la demande ajax pour définir l'en-tête. Ceci n'est requis que pour les postdemandes.

Le code pour lire le jeton csrf est disponible dans le rails/jquery-ujs, donc à mon humble avis, il est plus facile de simplement l'utiliser, comme suit:

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

Simple sans réimplémenter ce qui est déjà inclus par Rails. Ce devrait être la réponse choisie.
jiehanzheng

Dans Rails 5.1 fonctionne également:headers: { 'X-CSRF-Token': Rails.csrfToken() }
olhor

@nathanvda, vous pouvez peut-être répondre à cette question similaire: stackoverflow.com/questions/50159847/…


6

Les réponses les plus votées ici sont correctes mais ne fonctionneront pas si vous effectuez des demandes interdomaines car la session ne sera pas disponible à moins que vous ne demandiez explicitement à jQuery de passer le cookie de session. Voici comment procéder:

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

Puis-je vous demander si vous pouvez répondre à cette question très similaire? stackoverflow.com/questions/50159847/…

5

Vous pouvez l'écrire globalement comme ci-dessous.

JS normal:

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

Script de café:

  $('#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

Oups..

J'ai raté la ligne suivante dans mon application.js

//= require jquery_ujs

Je l'ai remplacé et son fonctionnement ..

======= MISE À JOUR =========

Après 5 ans, je suis de retour avec la même erreur, maintenant j'ai de nouveaux Rails 5.1.6 , et j'ai retrouvé ce post. Tout comme le cercle de la vie.

Maintenant, quel était le problème: Rails 5.1 a supprimé la prise en charge de jquery et jquery_ujs par défaut, et a ajouté

//= require rails-ujs in application.js

Il fait les choses suivantes:

  1. forcer les dialogues de confirmation pour diverses actions;
  2. faire des demandes non GET à partir d'hyperliens;
  3. faire des formulaires ou des hyperliens soumettre des données de manière asynchrone avec Ajax;
  4. les boutons d'envoi sont automatiquement désactivés sur le formulaire d'envoi pour éviter un double-clic. (à partir de: https://github.com/rails/rails-ujs/tree/master )

Mais pourquoi n'inclut-il pas le jeton csrf pour la demande ajax? Si quelqu'un le sait en détail, commentez-moi. J'apprécie ça.

Quoi qu'il en soit, j'ai ajouté ce qui suit dans mon fichier js personnalisé pour le faire fonctionner (merci pour les autres réponses pour m'aider à atteindre ce code):

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

C'était aussi ce que je devais faire. La raison pour laquelle cela est apparu est que je construis une application React pour remplacer lentement une application Rails existante. Puisqu'il y a beaucoup de bruit javascript dans l'application existante, j'ai créé une disposition différente qui accède à un fichier javascript différent, mais je n'ai pas réussi à l'inclure jquery_ujs. C'était ça l'astuce.
Wylliam Judd

1
Oui, parfois Si nous manquons cela lors de la reprise, refactoriser quelque chose .. Il est difficile de trouver ce qui ne va pas. Parce que nous ne faisons rien manuellement pour le faire fonctionner, Rails l'inclut automatiquement. Nous le pensons déjà là. Merci pour ces sites sociaux Qn / Ans
Abhi

Vous pouvez peut-être répondre à cette question similaire: stackoverflow.com/questions/50159847/…

4

Si vous n'utilisez pas jQuery et utilisez quelque chose comme fetch API pour les requêtes, vous pouvez utiliser ce qui suit pour obtenir 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)
    })

Puis-je vous demander si vous pouvez répondre à cette question très similaire? stackoverflow.com/questions/50159847/…

4

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

  • Rails 5.1 ou version ultérieure

    $ yarn add jquery.csrf
    //= require jquery.csrf
  • Rails 5.0 ou avant

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

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


En 5.1 utilisant webpack, ça //= require jquery.csrfne marchera pas, non?. Au lieu de cela, j'ai utilisé le fichier pack js avec import 'jquery.csrf'. Notez que vous n'avez pas besoin de l'inclure avec une balise pack dans vos vues.
Damien Justin Šutevski

3

Si vous utilisez javascript avec jQuery pour générer le jeton dans votre formulaire, cela fonctionne:

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

De toute évidence, vous devez avoir le <%= csrf_meta_tag %>dans votre disposition Ruby.


2

Pour ceux d'entre vous qui ont besoin d'une réponse non jQuery, vous pouvez simplement ajouter ce qui suit:

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

Un exemple très simple peut être trouvé ici:

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

6
Cela n'utilise-t-il pas jQuery pour les sélecteurs?
Yule

2

J'ai eu du mal avec ce problème pendant des jours. Tout appel GET fonctionnait correctement, mais tous les PUT génèreraient une erreur «Impossible de vérifier l'authenticité du jeton CSRF». Mon site Web fonctionnait bien jusqu'à ce que j'aie ajouté un certificat SSL à nginx.

Je suis finalement tombé sur cette ligne manquante dans mes paramètres 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; 
}

Après avoir ajouté la ligne manquante "proxy_set_header X-Forwarded-Proto https;", toutes mes erreurs de jeton CSRF se terminent.

J'espère que cela aide quelqu'un d'autre qui se bat aussi la tête contre un mur. haha



0

J'utilise Rails 4.2.4 et je n'ai pas pu comprendre pourquoi je recevais:

Can't verify CSRF token authenticity

J'ai dans la mise en page:

<%= csrf_meta_tags %>

Dans le contrôleur:

protect_from_forgery with: :exception

Invoquer tcpdump -A -s 999 -i lo port 3000montrait l'en-tête en cours de définition (bien ajaxSetupqu'il n'ait pas besoin de définir les en-têtes avec - c'était déjà fait):

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

En fin de compte, cela a échoué car j'avais désactivé les cookies. CSRF ne fonctionne pas sans l'activation des cookies, c'est donc une autre cause possible si vous voyez cette erreur.


c'est très utile!
joehwang
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.