49 votes

Génération de jetons CSRF

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

En général, j'aimerais générer un jeton à partir d'un élément unique de données associé à 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 inclure la chaîne à hacher dans la demande également ? 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'elle était incluse dans chaque requête, la validation du jeton CSRF pouvait se faire. Étant donné qu'elle est nouvelle à chaque demande et qu'elle est uniquement intégrée à la page, un accès extérieur au jeton ne serait pas possible. La sécurité du jeton repose alors sur le fait que la $mySecretKey n'est connue que de moi.

S'agit-il d'une approche naïve ? Ai-je oublié une raison pour laquelle cela ne peut pas fonctionner ?

Gracias

12 votes

La solution proposée est vulnérable aux attaques par rejeu. La même combinaison de jeton et de clé fonctionnera indéfiniment.

0 votes

Bon point, @Matthew. Mais comment pouvons-nous être défendus dans le cas où le jeton a été généré par le serveur, mais que l'utilisateur n'est pas revenu sur notre serveur et que cela a été fait par un pirate avec le même sessionId+hash ? Ou est-ce impossible (sans comparer l'adresse IP, l'agent d'utilisateur, etc.) ?

29voto

blowdart Points 28735

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

Les jetons CSRF comportent 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. L'utilisation de l'expression "ailleurs" empêche une page d'être autonome.

Si vous incluez la chaîne à hacher dans la demande, alors la demande est autonome, et un attaquant n'a qu'à copier le formulaire, car il dispose des deux parties du jeton, et il n'y a donc aucune protection.

Le fait de le placer dans l'URL du formulaire signifie qu'il est autonome, l'attaquant n'ayant qu'à copier le formulaire et l'URL de soumission.

17 votes

Non, c'est faux. Une moitié pourrait être conservée en session, ou être déposée via un cookie. Il n'est pas nécessaire de le stocker sur le serveur, il est généralement basé sur un cookie, ce qui évite de devoir activer les sessions.

0 votes

Selon l'OWASP, il s'agit seulement d'une atténuation appelés "cookies de double soumission" owasp.org/index.php/

0 votes

Pouvez-vous expliquer ceci : "Si vous incluez la chaîne à hacher dans la demande, alors la demande est autonome, donc copier le formulaire est tout ce qu'un attaquant doit faire, car il a les deux parties du jeton, et donc il n'y a pas de protection." ?

8voto

michalzuber Points 700

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

2voto

Dor Points 3731

Le jeton CSRF est destiné à empêcher les modifications (non intentionnelles) des données, qui sont généralement appliquées aux demandes POST.

Ainsi, vous devez inclure le jeton CSRF pour chaque requête qui modifie les données (requête GET ou POST).

Ma question concerne générer des jetons lorsqu'il n'y a PAS données utilisateur uniques à utiliser. Aucune session disponibles, les cookies ne sont pas une option, l'adresse IP et d'autres choses de ce genre ne sont pas fiables.

Il suffit ensuite de créer un identifiant unique pour chaque visiteur. Incluez cet identifiant dans un cookie ou dans les URL (si les cookies sont désactivés).

Edit :

Considérons l'événement suivant :

Vous vous êtes connecté à votre compte Facebook et vous êtes ensuite entré sur un site Web quelconque.

Sur ce site, il y a un formulaire que vous soumettez, qui demande à votre navigateur d'envoyer une requête POST à votre compte Facebook.

Cette demande POST peut modifier votre mot de passe ou ajouter un commentaire, etc., car l'application Facebook vous a reconnu comme un utilisateur enregistré et connecté. (à moins qu'il n'y ait un autre mécanisme de blocage, comme CAPTCHA).

0 votes

Ajouter une partie du jeton à une URL, et avoir l'autre moitié dans le formulaire ne signifie aucune protection.

0 votes

Bien sûr que vous l'avez fait, "Inclure cet identifiant dans un cookie ou dans les URLs (si les cookies sont désactivés)." - vous dites de mettre l'identifiant dans l'URL, ce n'est tout simplement pas sûr.

0 votes

Je n'ai pas trouvé de meilleure idée pour stocker un identifiant de session lorsque les cookies sont désactivés.

2voto

dynax60 Points 102

Je pense que la meilleure idée est de faire un hash basé sur HMAC, c'est à dire de faire un hash crypté par un mot de passe de cette séquence : nom d'utilisateur+identifiant+heure. Le hash doit être différent à chaque demande, l'horodatage doit être si vous ne voulez pas avoir la possibilité de rejouer simplement le hash lors d'une attaque.

1voto

MyGGaN Points 717

Il suffit d'avoir le même "token" dans l'URL/le formulaire et dans le cookie. Cela signifie que votre page peut définir le cookie de jeton à la valeur qu'elle souhaite (de préférence une valeur aléatoire) par JavaScript, puis passer la même valeur dans toutes les demandes adressées à votre serveur (en tant qu'URI, paramètre ou champ de formulaire). Il n'est pas nécessaire que votre serveur génère le cookie.

Ce système est sûr tant que le navigateur n'autorise pas les pages d'un domaine à modifier/lire les cookies d'autres domaines, ce qui est supposé être assez sûr 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 détecté par des tentatives de CSRF (pourquoi prendre le risque ?). Bien que vous puissiez mettre plus de logique dans un jeton généré par le serveur, il n'est pas nécessaire d'empêcher CSRF.

(Si je me trompe, veuillez me le faire savoir).

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