ActionController :: InvalidAuthenticityToken

148

Voici une erreur, causée par un formulaire dans mon application Rails:

Processing UsersController#update (for **ip** at 2010-07-29 10:52:27) [PUT]
  Parameters: {"commit"=>"Update", "action"=>"update", "_method"=>"put", "authenticity_token"=>"ysiDvO5s7qhJQrnlSR2+f8jF1gxdB7T9I2ydxpRlSSk=", **more parameters**}

ActionController::InvalidAuthenticityToken (ActionController::InvalidAuthenticityToken):

Cela se produit pour chaque non- getdemande et, comme vous le voyez, authenticity_tokenest là.

Nikita Rybak
la source

Réponses:

207

J'ai eu le même problème mais avec des pages qui ont été mises en cache. Les pages ont été mises en mémoire tampon avec un jeton d'authenticité périmé et toutes les actions utilisant les méthodes post / put / delete étaient reconnues comme des tentatives de falsification. L'erreur (422 entité impossible à traiter) a été renvoyée à l'utilisateur.

La solution pour Rails 3:
Ajouter:

 skip_before_filter :verify_authenticity_token  

ou comme "sagivo" l'a souligné dans Rails 4, ajoutez:

 skip_before_action :verify_authenticity_token

Sur les pages qui mettent en cache.

Comme @toobulkeh ce n'est pas commenté une vulnérabilité sur :index, des :showactions, mais méfiez - vous utiliser ce sur :put, des :postactions.

Par exemple:

 caches_page :index, :show  
 skip_before_filter :verify_authenticity_token, :only => [:index, :show]

Référence: http://api.rubyonrails.org/classes/ActionController/RequestForgeryProtection/ClassMethods.html

Note ajoutée par barlop- Rails 4.2 obsolète skip_before_filter au profit de skip_before_action https://guides.rubyonrails.org/4_2_release_notes.html "La famille de méthodes * _filter a été supprimée de la documentation. Leur utilisation est déconseillée au profit de l'action * _ famille de méthodes "

Pour Rails 6 (comme "collimarco" l'a souligné), vous pouvez l'utiliser skip_forgery_protectionet il est sûr de l'utiliser pour une API REST qui n'utilise pas de données de session.

Szymon Jeż
la source
3
Ce n'est probablement pas le cas, je ne connaissais pas caches_page avant votre publication. Mais je vais vérifier caches_page , merci.
Nikita Rybak
7
in rails 4skip_before_action :verify_authenticity_token
Sagiv Ofek
88
N'est-ce pas une vulnérabilité?
quantumpotato
6
ce n'est pas une vulnérabilité sur les :index, :showactions. Mais méfiez-vous de mettre cela sur des :put, :postactions!
toobulkeh
14
même si je conviens que vous avez parfois des cas où cela est nécessaire (peut-être une fois dans la vie), mais vous devez réaliser que vous corrigez la sécurité en désactivant la sécurité. Non recommandé
équivalent8
77

Pour moi, la cause de ce problème sous Rails 4 était manquante,

<%= csrf_meta_tags %>

Ligne dans la mise en page de mon application principale. Je l'avais accidentellement supprimé lorsque j'ai réécrit ma mise en page.

Si ce n'est pas dans la mise en page principale, vous en aurez besoin dans n'importe quelle page sur laquelle vous souhaitez un jeton CSRF.

James McMahon
la source
2
Nous recevons également cette erreur. Mais c'est intermittent. Cela pourrait-il être la raison ou cela n'affecterait-il pas chaque demande avec une erreur?
Ryan-Neal Mes
@ Ryan-NealMes, si votre modèle ne contient pas cette ligne, vous obtiendrez l'erreur. Il est donc possible que certains de vos modèles l'aient et d'autres non.
James McMahon
1
@JamesMcMahon merci, j'ai compris que mon cas était en fait causé par des utilisateurs effaçant leurs cookies ou bloqués. J'ai beaucoup appris de cette question!
Ryan-Neal Mes
61

Il y a plusieurs causes à cette erreur, (concernant Rails 4).

1. Vérification <%= csrf_meta_tags %>présente dans la mise en page

2. Vérifiez que le jeton d'authenticité est envoyé avec les appels AJAX si vous utilisez l' form_forassistant avec remote: trueoption. Sinon, vous pouvez inclure la ligne avec <%= hidden_field_tag :authenticity_token, form_authenticity_token %>le bloc de formulaire.

3. Si la demande est envoyée à partir de la page mise en cache , utilisez la mise en cache de fragment pour exclure une partie de la page qui envoie la demande, par exemple, button_toetc. sinon le jeton sera périmé / invalide.

Je serais réticent à annuler la protection CSRF ...

GoodViber
la source
csrf_meta_tags doit être dans <head>? Comment puis-je être sûr qu'il n'est pas en conflit avec les turbolinks?
sparkle
37

L'ajout du authenticity_tokenformulaire a corrigé le problème pour moi.

<%= hidden_field_tag :authenticity_token, form_authenticity_token %>
Deepak Mahakale
la source
3
Rails censés envoyer le jeton par défaut. Nous ne voulons pas le spécifier explicitement. Je sens que le jeton est changé d'une manière ou d'une autre dans cette situation ici.
Abhi
1
Cependant, si vous avez créé votre formulaire sans utiliser d'aide, vous devez le mettre manuellement.
André Guimarães Sakata
30

Le jeton d'authenticité est une valeur aléatoire générée à votre avis pour prouver qu'une demande est soumise à partir d'un formulaire sur votre site, pas ailleurs. Cela protège contre les attaques CSRF:

http://en.wikipedia.org/wiki/Cross-site_request_forgery

Vérifiez qui est ce client / cette IP, il semble qu'ils utilisent votre site sans charger vos vues.

Si vous avez besoin de déboguer davantage, cette question est un bon point de départ: Comprendre le jeton d'authenticité des rails

Modifié pour expliquer: cela signifie qu'ils appellent l'action pour traiter votre soumission de formulaire sans jamais afficher votre formulaire sur votre site Web. Cela peut être malveillant (par exemple, publier des commentaires de spam) ou indiquer qu'un client tente d'utiliser directement l'API de votre service Web. Vous êtes le seul à pouvoir y répondre par la nature de votre produit et l'analyse de vos demandes.

Winfield
la source
1
Merci, mais je sais déjà ce qu'est le jeton d'authenticité. Vérifiez qui est ce client / cette IP, il semble qu'ils utilisent votre site sans charger vos vues. Pardon, que signifie «sans chargement de vues»?
Nikita Rybak
1
Je veux dire que quelqu'un (probablement un spammeur) pourrait soumettre des données à votre formulaire sans passer par l'interface utilisateur de votre application. Il est possible de le faire en utilisant un programme en ligne de commande tel que curl, par exemple.
John Topley
John a tout à fait raison. Cela signifie qu'ils appellent à l'action pour traiter votre soumission de formulaire sans jamais afficher votre formulaire sur votre site Web. Cela peut être malveillant (par exemple, publier des commentaires de spam) ou indiquer qu'un client tente d'utiliser directement l'API de votre service Web. Vous êtes le seul à pouvoir y répondre par la nature de votre produit et l'analyse de vos demandes.
Winfield
Ok, j'ai mal compris le commentaire de Winfield. Je pensais que l'application n'était pas configurée pour `` charger mes vues '' lorsque j'utilise le navigateur.
Nikita Rybak le
1
J'ai aussi eu une autre pensée, ces demandes incluent un jeton, mais ce n'est pas valide. Cela peut être dû à la mise en cache de la page qui rend votre formulaire ou à quelque chose d'autre qui provoque potentiellement une version obsolète du formulaire.
Winfield
27

ActionController::InvalidAuthenticityTokenpeut également être causé par un proxy inverse mal configuré. C'est le cas si dans la trace de pile, vous obtenez une ligne ressemblant à Request origin does not match request base_url.

Lors de l'utilisation d'un proxy inverse (tel que nginx) comme récepteur pour la requête HTTPS et de la transmission de la requête non chiffrée au backend (tel que l'application Rails), le backend (plus précisément: Rack) attend des en-têtes avec plus d'informations sur la demande client d'origine afin de pouvoir appliquer diverses tâches de traitement et mesures de sécurité.

Plus de détails sont disponibles ici: https://github.com/rails/rails/issues/22965 .

TL; DR: la solution est d'ajouter quelques en-têtes:

upstream myapp {
  server              unix:///path/to/puma.sock;
}

location / {
  proxy_pass        http://myapp;
  proxy_set_header  Host $host;
  proxy_set_header  X-Forwarded-For $proxy_add_x_forwarded_for;
  proxy_set_header  X-Forwarded-Proto $scheme;
  proxy_set_header  X-Forwarded-Ssl on; # Optional
  proxy_set_header  X-Forwarded-Port $server_port;
  proxy_set_header  X-Forwarded-Host $host;
}
vmarquet
la source
Wow, j'ai cherché 3 heures pour une solution pour cela, et c'était tout, merci!
evexoio
merci beaucoup 6 heures d'essayer de résoudre ce problème côté rails
Joe Half Face
18

trop tard pour répondre mais j'ai trouvé la solution.

Lorsque vous définissez votre propre formulaire html, vous manquez la chaîne de jeton d'authentification qui devrait être envoyée au contrôleur pour des raisons de sécurité. Mais lorsque vous utilisez l'assistant de formulaire de rails pour générer un formulaire, vous obtenez quelque chose comme suit

<form accept-charset="UTF-8" action="/login/signin" method="post">
  <div style="display:none">
    <input name="utf8" type="hidden" value="&#x2713;">
    <input name="authenticity_token" type="hidden" 
      value="x37DrAAwyIIb7s+w2+AdoCR8cAJIpQhIetKRrPgG5VA=">
    .
    .
    .
  </div>
</form>

La solution au problème est donc soit d'ajouter le champ authenticity_token, soit d'utiliser des rails pour les helpers plutôt que de supprimer, de déclasser ou de mettre à niveau les rails.

amjad
la source
9

Si vous avez effectué une rake rails:updatemodification ou avez récemment modifié votre config/initializers/session_store.rb, cela peut être un symptôme d'anciens cookies dans le navigateur. J'espère que cela se fait dans dev / test (c'était pour moi), et vous pouvez simplement effacer tous les cookies de navigateur liés au domaine en question.

Si cela est en production et que vous avez changé key, envisagez de le modifier pour utiliser les anciens cookies (<- juste spéculation).

Kross
la source
Oui! Pour moi, avoir un session_store.rb vide provoquait l'erreur.
lafeber
6

J'ai eu ce problème avec les appels javascript. J'ai corrigé cela en nécessitant simplement jquery_ujs dans le fichier application.js.

Michael Koper
la source
Oui correct, j'ai également eu ce problème et j'ai ajouté jquery_ujs dans l'application js. Ça a marché.
Abhi
3

Nous avons eu le même problème, mais avons remarqué que c'était uniquement pour les requêtes utilisant http: // et non avec https: //. La cause était secure: truepour session_store:

Rails.application.config.session_store(
  :cookie_store,
  key: '_foo_session',
  domain: '.example.com',
  secure: true
)

Corrigé en utilisant HTTPS ~ partout :)

Darep
la source
J'ai rencontré cela lors de l'utilisation rails s(non SSL) au lieu du point de terminaison SSL que j'ai configuré pour le développement. Ce n'est que lorsque j'ai lu votre commentaire que j'ai réalisé ce que je faisais. Une fois que je suis revenu à l'utilisation de SSL, les choses ont recommencé à fonctionner. Merci!
Karl Wilbur
1
J'ai fait face à ce problème dans le développement. Au lieu de secure: truemoi écritsecure: !Rails.env.development?
murb
1

Pour les rails 5, il vaut mieux ajouter protect_from_forgery prepend: trueque sauter leverify_authentication_token

aadeshere1
la source
5
Pourquoi? Pouvez-vous ajouter une référence?
kwerle
1

Ajouter

//= require rails-ujs 

dans

\app\assets\javascripts\application.js
Maicon Douglas
la source
0

J'ai eu ce problème et la raison était que j'ai copié et collé un contrôleur dans mon application. J'avais besoin de changer ApplicationControllerpourApplicationController::Base

user2954587
la source
0

J'ai eu le même problème sur localhost. J'ai changé le domaine de l'application, mais dans le fichier des URL et des hôtes, il y avait toujours l'ancien domaine. J'ai mis à jour le fichier de favoris et d'hôtes de mon navigateur pour utiliser un nouveau domaine et maintenant tout fonctionne bien.

MoD
la source
0

Peut-être avez-vous votre configuration NGINX pour HTTPS mais vos certificats ne sont pas valides? J'ai eu un problème similaire dans le passé et la redirection de http vers https a résolu le problème

montréal
la source
0

J'ai vérifié que les <% = csrf_meta_tags%> sont présents et la suppression des cookies dans le navigateur a fonctionné pour moi.

Praveen KJ
la source
0

Suite aux recommandations de Chrome Lighthouse pour un chargement plus rapide des applications, j'ai asynchronisé mon Javascript:

views/layout/application.html.erb

<%= javascript_include_tag 'application', 'data-turbolinks-track' => 'reload', async: true %>

Cela a tout cassé et obtenu cette erreur de jeton pour mes formulaires distants. La suppression a async: truerésolu le problème.

Maxence
la source
0

Cette réponse est beaucoup plus spécifique à Ruby on Rails, mais j'espère qu'elle aidera quelqu'un.

Vous devez inclure le jeton CSRF avec chaque requête non GET. Si vous avez l'habitude d'utiliser JQuery, Rails a une bibliothèque d'aide appelée jquery-ujsqui se construit au-dessus et ajoute des fonctionnalités cachées. L'une des choses qu'il fait est d'inclure automatiquement le jeton CSRF dans chaque ajaxdemande. Regardez ici .

Si vous vous en éloignez comme je l'ai fait, vous pourriez vous retrouver avec une erreur. Vous pouvez simplement soumettre le jeton manuellement ou utiliser une autre bibliothèque pour aider à extraire le jeton du DOM. Voir cet article pour plus de détails.

user2490003
la source
0

Pour l'environnement de développement, j'ai essayé plusieurs de ces tentatives pour résoudre ce problème, dans Rails 6. Aucune d'elles n'a aidé. Donc, si aucune de ces suggestions n'a fonctionné pour vous, essayez ci-dessous.

La seule solution que j'ai trouvée était d'ajouter un fichier txt dans votre dossier / tmp.

Dans le répertoire racine de votre application, exécutez:

touch tmp/caching-dev.txt

Ou créez manuellement un fichier portant ce nom dans votre dossier / tmp. Puisque cela l'a résolu pour moi, je suppose que la racine du problème est un conflit de mise en cache.

Twistedben
la source
-1

Dans les rails 5, nous devons ajouter 2 lignes de code

    skip_before_action :verify_authenticity_token
    protect_from_forgery prepend: true, with: :exception
Giapnh
la source
-2

Installation

gem 'remotipart' 

peut aider

Alexei.B
la source
3
bien que cela puisse être la réponse, mais il est également utile d'inclure la partie essentielle de la réponse et d'expliquer pourquoi / comment cela fonctionne.
Roy Lee
-15

Problème résolu en rétrogradant à 2.3.5 à partir de 2.3.8. (ainsi que le tristement célèbre problème «Vous êtes redirigé»)

Nikita Rybak
la source
@Flip est-ce peut-être une idée de mettre à jour la réponse acceptée?
lafeber le