131 votes

Rails CSRF Protection + Angular.js: protect_from_forgery me permet de me déconnecter du POST

Si l'option protect_from_forgery est mentionnée dans application_controller, je peux me connecter et exécuter toute demande GET, mais lors de la toute première demande POST, Rails réinitialise la session, ce qui me déconnecte.

J'ai désactivé temporairement l'option protect_from_forgery , mais j'aimerais l'utiliser avec Angular.js. Y a-t-il un moyen de faire ça?

278voto

HungYuHei Points 1716

Je pense que la lecture de CSRF-valeur de DOM n'est pas une bonne solution, c'est juste une solution de contournement.

Voici un document formulaire angularJS site officiel http://docs.angularjs.org/api/ng.$http :

Depuis JavaScript qui s'exécute sur votre nom de domaine pourrait lire le cookie, votre serveur peut être assuré que le XHR est venu à partir de JavaScript en cours d'exécution sur votre domaine.

Pour profiter de cette (Protection CSRF), votre serveur doit mettre un jeton dans un JavaScript lisible session cookie appelé XSRF-JETON sur la première requête HTTP GET. Sur les les demandes non-GET le serveur peut vérifier que le témoin correspond à X-XSRF-JETON en-tête HTTP

Voici ma solution basée sur ces instructions:

Tout d'abord, placer le biscuit:

# app/controllers/application_controller.rb

# Turn on request forgery protection
protect_from_forgery

after_filter :set_csrf_cookie_for_ng

def set_csrf_cookie_for_ng
  cookies['XSRF-TOKEN'] = form_authenticity_token if protect_against_forgery?
end

Ensuite, nous devons vérifier le pion à tous les non-GET.
Depuis des Rails a déjà construit avec la même méthode, on peut tout simplement remplacer pour ajouter notre logique:

# app/controllers/application_controller.rb

protected

  def verified_request?
    super || form_authenticity_token == request.headers['X-XSRF-TOKEN']
  end

78voto

Brandon Tilley Points 49142

Si vous utilisez la valeur par défaut de Rails de protection CSRF (<%= csrf_meta_tags %>), vous pouvez configurer votre Angulaire module comme ceci:

myAngularApp.config ["$httpProvider", ($httpProvider) ->
  $httpProvider.defaults.headers.common['X-CSRF-Token'] = $('meta[name=csrf-token]').attr('content')
]

Ou, si vous n'êtes pas à l'aide de CoffeeScript (quoi!?):

myAngularApp.config([
  "$httpProvider", function($httpProvider) {
    $httpProvider.defaults.headers.common['X-CSRF-Token'] = $('meta[name=csrf-token]').attr('content');
  }
]);

Si vous préférez, vous pouvez envoyer l'en-tête uniquement sur les demandes non-GET avec quelque chose comme ce qui suit:

myAngularApp.config ["$httpProvider", ($httpProvider) ->
  csrfToken = $('meta[name=csrf-token]').attr('content')
  $httpProvider.defaults.headers.post['X-CSRF-Token'] = csrfToken
  $httpProvider.defaults.headers.put['X-CSRF-Token'] = csrfToken
  $httpProvider.defaults.headers.patch['X-CSRF-Token'] = csrfToken
  $httpProvider.defaults.headers.delete['X-CSRF-Token'] = csrfToken
]

Aussi, assurez-vous de vérifier HungYuHei réponse, qui couvre toutes les bases sur le serveur plutôt que sur le client.

29voto

jsanders Points 309

La gem angular_rails_csrf ajoute automatiquement la prise en charge du modèle décrit dans la réponse de HungYuHei à tous vos contrôleurs:

 # Gemfile
gem 'angular_rails_csrf'
 

1voto

Blaine Hatab Points 252

J'ai vu les autres réponses et de la pensée qu'ils étaient grands et bien pensé. J'ai obtenu mon application rails de travail mais avec ce que j'ai pensé a une solution plus simple alors j'ai pensé que je devais partager. Mon application rails, est venu avec cette souffrance,

class ApplicationController < ActionController::Base
  # Prevent CSRF attacks by raising an exception.
  # For APIs, you may want to use :null_session instead.
  protect_from_forgery with: :exception
end

J'ai lu les commentaires et il me semblait que c'est ce que je veux utiliser angulaire et d'éviter les csrf erreur. Je l'ai changé pour cela,

class ApplicationController < ActionController::Base
  # Prevent CSRF attacks by raising an exception.
  # For APIs, you may want to use :null_session instead.
  protect_from_forgery with: :null_session
end

Et maintenant ça fonctionne! Je ne vois pas pourquoi cela ne fonctionnerait pas, mais j'aimerais entendre un aperçu de autres affiches.

1voto

PaulL Points 714

J'ai utilisé le contenu de HungYuHei de répondre à ma demande. J'ai trouvé que j'avais affaire à quelques questions supplémentaires toutefois, certains à cause de mon utilisation de Concevoir pour l'authentification, et certains en raison de la valeur par défaut que j'ai eu avec ma demande:

protect_from_forgery with: :exception

Je note la relative débordement de pile question et les réponses, et j'ai écrit beaucoup plus de commentaires de blog qui résume les diverses considérations. Les éléments de solution qui sont pertinentes en l'espèce sont, dans le contrôleur de l'application:

  protect_from_forgery with: :exception

  after_filter :set_csrf_cookie_for_ng

  def set_csrf_cookie_for_ng
    cookies['XSRF-TOKEN'] = form_authenticity_token if protect_against_forgery?
  end

  rescue_from ActionController::InvalidAuthenticityToken do |exception|
    cookies['XSRF-TOKEN'] = form_authenticity_token if protect_against_forgery?
    render :error => 'Invalid authenticity token', {:status => :unprocessable_entity} 
  end

protected
  def verified_request?
    super || form_authenticity_token == request.headers['X-XSRF-TOKEN']
  end

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X