web-dev-qa-db-fra.com

Génération de jetons CSRF

Il s'agit d'une question sur la génération de jetons CSRF.

Habituellement, j'aimerais générer un jeton basé sur une donnée unique associée à la session de l'utilisateur, et haché et salé avec une clé secrète.

Ma question concerne la génération de jetons lorsqu'il n'y a PAS de données utilisateur uniques à utiliser. Aucune session n'est disponible, les cookies ne sont pas une option, l'adresse IP et les choses de cette nature ne sont pas fiables.

Y a-t-il une raison pour laquelle je ne peux pas également inclure la chaîne à hacher dans la demande? Exemple de pseudocode pour générer le jeton et l'intégrer:

var $stringToHash = random()
var $csrfToken = hash($stringToHash + $mySecretKey)
<a href="http://foo.com?csrfToken={$csrfToken}&key={$stringToHash}">click me</a>

Exemple de validation côté serveur du jeton CSRF

var $stringToHash = request.get('key')
var $isValidToken = hash($stringToHash + $mySecrtKey) == request.get('csrfToken')

La chaîne utilisée dans le hachage serait différente à chaque demande. Tant qu'il était inclus dans chaque demande, la validation du jeton CSRF pouvait se poursuivre. Comme il est nouveau à chaque demande et uniquement intégré à la page, l'accès extérieur au jeton ne serait pas disponible. La sécurité du jeton revient alors à $ mySecretKey qui n'est connu que de moi.

Est-ce une approche naïve? Me manque-t-il une raison pour laquelle cela ne peut pas fonctionner?

Merci

44
Jim Beam

Y a-t-il une raison pour laquelle je ne peux pas également inclure la chaîne à hacher dans la demande?

Les jetons CSRF ont deux parties. Le jeton intégré dans le formulaire et un jeton correspondant ailleurs, que ce soit dans un cookie, stocké dans une session ou ailleurs. Cette utilisation d'ailleurs empêche une page d'être autonome.

Si vous incluez la chaîne à hacher dans la demande, la demande est autonome, donc la copie du formulaire est tout ce qu'un attaquant doit faire, car ils ont les deux parties du jeton, et donc il n'y a pas de protection.

Même le mettre dans l'URL du formulaire signifie qu'il est autonome, l'attaquant copie simplement le formulaire et l'URL de soumission.

28
blowdart

Essayez base64_encode(openssl_random_pseudo_bytes(16)). https://github.com/codeguy/php-the-right-way/issues/272#issuecomment-18688498 et je l'ai utilisé pour mon exemple de formulaire dans https: // Gist .github.com/mikaelz/5668195

7
michalzuber

Jeton CSRF destiné à empêcher les modifications de données (non intentionnelles), qui sont généralement appliquées avec les demandes POST.

Ainsi, vous devez inclure un jeton CSRF pour chaque demande qui modifie des données (soit GET soit POST).

Ma question concerne la génération de jetons lorsqu'il n'y a PAS de données utilisateur uniques à utiliser. Aucune session n'est disponible, les cookies ne sont pas une option, l'adresse IP et les choses de cette nature ne sont pas fiables.

Créez ensuite simplement un identifiant utilisateur unique pour chaque visiteur. Incluez cet identifiant dans un cookie ou dans les URL (si les cookies sont désactivés).

Modifier:

Considérez l'événement suivant:

Vous vous êtes connecté à votre compte Facebook, puis vous êtes entré sur un site Web arbitraire.

Sur ce site Web, vous soumettez un formulaire qui indique à votre navigateur d'envoyer une demande POST à votre compte Facebook).

Cette POST peut changer votre mot de passe ou ajouter un commentaire, etc., car l'application Facebook vous a reconnu comme un utilisateur enregistré et connecté. (Sauf s'il existe un autre mécanisme de blocage, comme CAPTCHA)

2
Dor

Vous avez simplement besoin du même "token" dans l'URL/formulaire et dans le cookie. Cela signifie que votre page peut définir le cookie de jeton sur ce qu'il veut (de préférence une valeur aléatoire) par JavaScript, puis passer la même valeur dans toutes les demandes qui vont à votre serveur (en tant que paramètre ou formulaire URI? champ). Pas besoin que votre serveur génère le cookie.

Ceci est sûr tant que nous espérons que le navigateur n'autorise pas les pages d'un domaine à éditer/lire les cookies pour d'autres domaines, et cela est supposé être assez sécurisé aujourd'hui.

Le fait que votre serveur génère le jeton suppose que ce jeton peut être transmis en toute sécurité à votre navigateur sans être récupéré par des tentatives CSRF (pourquoi prendre le risque?). Bien que vous puissiez mettre plus de logique dans un jeton généré par le serveur, mais pour éviter CSRF, il n'y a pas besoin.

(Si je me trompe ici, faites-le moi savoir)

1
MyGGaN

Il existe plusieurs implémentations du jeton CSRF. L'essentiel est de savoir si ce jeton csrf est généré côté client ou côté serveur. Parce que l'implémentation change radicalement pour ces deux scénarios et l'entropie du jeton également.

Côté serveur, SecureRandom est le moyen préféré mais dans votre cas, vous souhaitez générer le jeton CSRF avant qu'un utilisateur ne soit identifié, window.crypto fournit cette fonctionnalité où vous pouvez générer un chaîne assez impossible à deviner pour être utilisée pour le jeton CSRF.

1
user1744119

Je veux dire que votre approche fonctionne, parce que l'attaque CSRF est l'attaquant utilisant le navigateur de la victime pour se forger un statut connecté, pourquoi peuvent-ils le faire? car sur la plupart des serveurs, la vérification de session est basée sur un SessionID dans le cookie, et le cookie est un élément de données qui sera automatiquement joint à une requête HTTP envoyée au serveur.

Par conséquent, il existe deux facteurs clés pour défendre la CSRF

  1. Générez un jeton de défi et demandez au client de le transmettre au serveur sans cookie, soit URL param soit POST est correct.
  2. Gardez le jeton en sécurité comme ce que vous avez fait pour le SessionID, par exemple, en utilisant SSL.

Je recommande la lecture Aide-mémoire sur la prévention CSRF

1
Frank Zhang

Je pense que la meilleure idée de faire du hachage basé sur HMAC, c'est-à-dire de faire du hachage chiffré par un mot de passe de cette séquence: nom d'utilisateur + id_utilisateur + horodatage. À chaque demande, le hachage doit être différent, l'horodatage doit l'être si vous ne voulez pas obtenir une simple relecture du hachage en attaque.

0
dynax60