web-dev-qa-db-fra.com

Application monopage et jeton CSRF

J'ai besoin d'utiliser une application de page unique (React, Ember, Angular, je m'en fiche) avec Rails mécanisme de protection CSRF.

Je me demande si j'ai besoin de créer une heure de jeton dans le ApplicationController comme ceci:

class ApplicationController < ActionController::Base

  after_action :set_csrf_cookie

  def set_csrf_cookie
    cookies["X-CSRF-Token"] = form_authenticity_token
  end

end

ou je peux simplement créer un jeton une fois.

Par session ou par demande (non-GET)?

Je pense que le jeton est toujours valide jusqu'à ce que la session soit valide, non?

CLARIFIER :

Je vois Rails application par défaut (pages rendues par le serveur) mettre à jour le jeton csrf chaque fois que je navigue sur une page. Donc à chaque fois qu'elle change.

Donc, dans ma situation, si je crée un nouveau jeton pour chaque after_action l'ancien jeton CSRF est toujours valable pour cette session. Alors, comment invalider le jeton précédent? Je dois?

Parce que seulement si j'invalide cela a du sens, non?

5
user4412054

Côté client (SPA)

Vous n'avez besoin de récupérer le jeton CSRF qu'une fois par session . Vous pouvez le conserver dans le navigateur et l'envoyer à chaque demande (non GET).

Rails apparaîtra pour générer un nouveau jeton CSRF à chaque demande, mais il acceptera tout jeton généré à partir de cette session. En réalité, il ne fait que masquer un seul jeton à l'aide d'un tampon unique par demande, afin de se protéger contre les attaques SSL BREACH. Plus de détails sur https://stackoverflow.com/a/49783739/2016618 . Vous n'avez pas besoin de suivre/stocker ces jetons.

Du côté serveur

Je suggère fortement d'utiliser le protect_from_forgery directive plutôt que de coder vous-même le jeton CSRF dans un en-tête. Il générera un jeton masqué différent par demande.

Vous pouvez certainement le reproduire vous-même avec peu de code, mais je ne vois pas pourquoi vous en auriez besoin.

Avez-vous besoin d'une protection CSRF avec une API?

Oui! Si vous vous authentifiez avec un cookie, vous avez besoin d'une protection CSRF. Cela est dû au fait que les cookies sont envoyés à chaque demande, donc un site Web malveillant pourrait envoyer une demande POST à votre site et effectuer des demandes au nom d'un utilisateur connecté. Le jeton CSRF empêche cela, car le site malveillant ne connaîtra pas le jeton CSRF.

3
Sarkom

Si vous utilisez l'application SPA, vous utilisez principalement votre Rails uniquement en tant qu'API. Le jeton CSRF a été conçu pour le rendu du serveur ... pas SPA. Dans SPA, vous utilisez déjà le jeton lors de l'authentification, donc pas besoin d'utiliser un autre jeton pour CSRF. CSRF a été conçu comme une protection pour les appels intersites, mais l'API elle-même conçue de manière à permettre la demande de n'importe où jusqu'à ce qu'ils soient authentifiés.

Il suffit de le désactiver pour votre API et c'est tout. J'irais avec un espace de noms API et j'installerais un BaseController, qui sera hérité pour tous les contrôleurs d'API. Là, vous devez définir protect_from_forgery:

class API::BaseController < ApplicationController
  protect_from_forgery with: :null_session
end
1
AntonTkachov

Je vais juste répondre à la question. Tous les détails sont expliqués dans cet article: https://blog.eq8.eu/article/Rails-api-authentication-with-spa-csrf-tokens.html

Compte tenu de Rails définit un cookie pour SPA

Les jetons CSRF sont valides pendant la durée de vie de la session. Par conséquent, oui, il est juste de générer un jeton CSRF pour la durée de la session après la connexion.

class LoginController < ApplicationController
  def create
    if user_password_match
      # ....
      cookie[:my_csrf_token]= form_authenticity_token
    end
  end
end

ou vous pouvez actualiser le cookie de la même manière que vous proposez

class ApplicationController < ActionController::Base

  after_action :set_csrf_cookie

  def set_csrf_cookie
    cookies["my_csrf_token"] = form_authenticity_token
  end

end

Votre SPA a juste besoin de lire le cookie et de le définir comme en-tête.

Les deux sont également valables

ou Vous pouvez simplement fournir le jeton CSRF comme réponse de connexion et SPA le stockera quelque part et l'utilisera dans le X-CSRF-Token entête:

curl POST  https://api.my-app.com/login.json  -d "{"email":'[email protected]", "password":"Hello"}"  -H 'ContentType: application/json'
# Cookie with session_id was set

# response:

{  "login": "ok", "csrf": 'yyyyyyyyy" }

# next request 

 curl POST  https://api.my-app.com/transfer_my_money  -d "{"to_user_id:":"1234"}"  -H "ContentType: application/json" -H "X-CSRF-Token: yyyyyyyyy"

Étant donné Rails accepte l'authentification d'en-tête uniquement

si vous n'utilisez pas de cookie pour envoyer session_id, votre API utilise donc juste l'en-tête Authentication pour l'authentification. Ensuite, vous n'avez pas besoin de protection CSRF.

Aucun cookie de session, aucun problème CSRF!

Exemple:

curl POST  https://api.my-app.com/login.json  -d "{"email":'[email protected]", "password":"Hello"}"  -H 'ContentType: application/json'
# No cookie/session is set

# response:
{ "login": "ok", "jwt": "xxxxxxxxxxx.xxxxxxxx.xxxxx" }

# Next Request:
curl POST  https://api.my-app.com/transfer_my_money  -d "{"to_user_id:":"1234"}"  -H "ContentType: application/json" -H "Authentication: Bearer xxxxxxxxxxx.xxxxxxxx.xxxxx"

Encore une fois, ce n'est que lorsque vous n'utilisez pas de cookies pour l'identification des utilisateurs! Donc CSRF n'est pas un problème dans ce cas mais vous vous protégez toujours contre les attaques de script intersite, assurez-vous que votre communication est uniquement HTTP, etc ...

1
equivalent8

Je ne sais pas à quel problème exact vous êtes confronté. Mais si vous rencontrez des problèmes CSRF dans les nouvelles versions Rails et devez inclure Rails CSRF dans les requêtes ajax, vous pouvez suivre les étapes ci-dessous).

Récemment, j'ai utilisé Rails 5.1 application.

Lors de l'utilisation d'appels ajax pour récupérer des données à partir d'API, je rencontrais des problèmes de jeton CSRF:

‘WARNING: Can't verify CSRF token authenticity Rails’

La raison était

Rails 5.1 a supprimé la prise en charge de jquery et jquery_ujs par défaut, et 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 il n'inclut pas le jeton csrf pour la demande ajax par défaut. Méfiez-vous de cela. Nous devons le passer explicitement comme:

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

Notez que dans la version Rails 5.1, vous obtenez la classe ‘Rails’ en js et pouvez utiliser les fonctions.

Mise à jour: Si vous utilisez Rails côté serveur et autre frontal, vous ne voulez vraiment pas utiliser = Rails a fourni des jetons CSRF. Parce que ce n'est vraiment pas important le service backend que vous utilisez.

Si votre objectif est de bloquer CSRF, vous devez configurer CORS dans le backend, c'est-à-dire votre Rails backend. Rails fournit maintenant un fichier séparé dans l'initialiseur) Vous pouvez mentionner quels sites sont autorisés à envoyer des requêtes ajax à votre backend.

Modifiez ici:

config/initializers/cors.rb

Si vous souhaitez une authentification, utilisez l'authentification de base, l'authentification par jeton ou JWT

1
Abhi