web-dev-qa-db-fra.com

Rails 4 Jeton d'authenticité

Je travaillais sur une nouvelle application Rails 4 (sur Ruby 2.0.0-p0) lorsque j'ai rencontré un problème de jeton d'authenticité.

Lors de l'écriture d'un contrôleur qui répond à json (à l'aide de la méthode respond_to class), je suis arrivé à l'action create J'ai commencé à obtenir des exceptions ActionController::InvalidAuthenticityToken lorsque j'ai tenté de créer un enregistrement à l'aide de curl.

Je me suis assuré de régler -H "Content-Type: application/json" et les données avec -d "<my data here>" mais toujours pas de chance.

J'ai essayé d'écrire le même contrôleur en utilisant Rails 3.2 (sur Ruby 1.9.3) et je n'ai aucun problème de jeton d'authenticité. J'ai cherché autour et j'ai vu qu'il y avait quelques changements avec les jetons d'authenticité dans Rails 4. D'après ce que je comprends, ils ne sont plus automatiquement insérés dans les formulaires? Je suppose que cela concerne en quelque sorte les types de contenu non HTML.

Existe-t-il un moyen de résoudre ce problème sans avoir à demander un formulaire HTML, en saisissant le jeton d'authenticité, puis en faisant une autre demande avec ce jeton? Ou est-ce que je manque complètement quelque chose qui est complètement évident?

Edit: Je viens d'essayer de créer un nouvel enregistrement dans une nouvelle application Rails 4 en utilisant un échafaudage sans rien changer et je rencontre le même problème, alors je suppose que ce n'est pas fait.

197
alexcoco

Je pense que je viens de le comprendre. J'ai changé le (nouveau) défaut

protect_from_forgery with: :exception

à

protect_from_forgery with: :null_session

selon le commentaire dans ApplicationController.

# Prevent CSRF attacks by raising an exception.
# For APIs, you may want to use :null_session instead.

Vous pouvez voir la différence en regardant la source de request_forgery_protecton.rb, ou plus précisément les lignes suivantes:

Dans Rails 3.2 :

# This is the method that defines the application behavior when a request is found to be unverified.
# By default, \Rails resets the session when it finds an unverified request.
def handle_unverified_request
  reset_session
end

Dans Rails 4 :

def handle_unverified_request
  forgery_protection_strategy.new(self).handle_unverified_request
end

Qui appellera le suivant :

def handle_unverified_request
  raise ActionController::InvalidAuthenticityToken
end
274
alexcoco

Au lieu de désactiver la protection csrf, il est préférable d’ajouter la ligne de code suivante dans le formulaire.

<%= tag(:input, :type => "hidden", :name => request_forgery_protection_token.to_s, :value => form_authenticity_token) %> 

et si vous utilisez form_for ou form_tag pour générer le formulaire, il ajoutera automatiquement la ligne de code ci-dessus dans le formulaire.

71
xiaoboa

L'ajout de la ligne suivante dans le formulaire a fonctionné pour moi:

<%= hidden_field_tag :authenticity_token, form_authenticity_token %>
70
Carlos

Je ne pense pas qu'il soit bon de désactiver généralement la protection CSRF tant que vous n'implémentez pas exclusivement une API.

Lors de l'examen de la documentation de l'API Rails 4 pour ActionController , j'ai constaté que vous pouviez désactiver la protection contre la falsification sur un contrôleur ou une base de méthodes.

Par exemple, pour désactiver la protection CSRF des méthodes que vous pouvez utiliser

class FooController < ApplicationController
  protect_from_forgery except: :index
32
roamingthings

Je suis tombé sur le même problème. Corrigé en ajoutant à mon contrôleur:

      skip_before_filter :verify_authenticity_token, if: :json_request?
8
user1756254

As-tu essayé?

 protect_from_forgery with: :null_session, if: Proc.new {|c| c.request.format.json? }
7
zechtz

Ce document officiel - explique comment désactiver correctement la protection contre la falsification de l’API http://api.rubyonrails.org/classes/ActionController/RequestForgeryProtection.html

4
konung

Ceci est une fonctionnalité de sécurité dans Rails. Ajoutez cette ligne de code sous la forme:

<%= hidden_field_tag :authenticity_token, form_authenticity_token %>

La documentation peut être trouvée ici: http://api.rubyonrails.org/classes/ActionController/RequestForgeryProtection.html

3
B Liu

Ces fonctionnalités ont été ajoutées à des fins de sécurité et de protection contre la falsification.
Cependant, pour répondre à votre question, voici quelques entrées. Vous pouvez ajouter ces lignes après le nom du contrôleur.

Ainsi,

class NameController < ApplicationController
    skip_before_action :verify_authenticity_token

Voici quelques lignes pour différentes versions de Rails.

Rails

skip_before_filter: verify_authenticity_token

Rails 4:

skip_before_action: verify_authenticity_token


Si vous souhaitez désactiver cette fonctionnalité de sécurité pour toutes les routines de contrôleur, vous pouvez modifier la valeur de protect_from_forgery en : null_session sur votre fichier application_controller.rb.

Ainsi,

class ApplicationController < ActionController::Base
  protect_from_forgery with: :null_session
end
2
Kent Aguilar

Ajouter authenticity_token: true à la balise de formulaire

1
Salma Gomaa

Si vous utilisez jQuery avec Rails, veillez à ne pas autoriser la saisie de méthodes sans vérifier le jeton d'authenticité.

jquery-ujs peut gérer les jetons pour vous

Vous devriez déjà l'avoir dans le gem jquery-Rails, mais vous devrez peut-être l'inclure dans application.js avec

//= require jquery_ujs

C'est tout ce dont vous avez besoin - votre appel ajax devrait maintenant fonctionner

Pour plus d'informations, voir: https://github.com/Rails/jquery-ujs

1
user1555400

Tous mes tests fonctionnaient bien. Mais pour une raison quelconque, j'avais défini ma variable d'environnement sur non-test:

export Rails_ENV=something_non_test

J'ai oublié de désélectionner cette variable à cause de laquelle j'ai commencé à obtenir une exception ActionController::InvalidAuthenticityToken.

Après avoir désactivé $Rails_ENV, mes tests ont recommencé à fonctionner.

0
mridula

Lorsque vous définissez votre propre formulaire html, vous devez inclure une chaîne de jeton d'authentification, qui doit être envoyée au contrôleur pour des raisons de sécurité. Si vous utilisez Rails l'assistant de formulaire pour générer le jeton d'authenticité est ajouté au formulaire 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 consiste donc à ajouter un champ authenticity_token ou à utiliser Rails form helpers plutôt que de compromettre la sécurité, etc.

0
amjad