web-dev-qa-db-fra.com

Quelle est la bonne façon d'implémenter des jetons de formulaire anti-CSRF?

Je suis pleinement conscient de CSRF et j'ai déjà implémenté des formulaires sûrs, mais je n'ai jamais été satisfait des résultats.

J'ai créé des jetons en tant que md5 de nom d'utilisateur, d'informations de formulaire et de sel et les ai stockés dans une session. Cela a un problème avec la navigation par onglets (peut être corrigée en conservant un tableau de hachages actifs) et avec le timing. Je voudrais que mes hachages fonctionnent uniquement par exemple. 10 minutes, mais comment puis-je mettre une variable liée au temps dans le hachage?

Quelqu'un peut-il m'indiquer une bonne ressource décrivant comment rendre la sécurité CSRF correctement?

34
naugtur

La meilleure façon de construire correctement la protection CSRF:

Non.

La plupart des frameworks courants ont déjà cette protection intégrée (ASP.NET, Struts, Ruby je pense), ou il y a des bibliothèques existantes qui ont déjà été vérifiées (par exemple CSRFGuard de OWASP ).

Une autre option, selon votre contexte, consiste à imposer une nouvelle authentification de l'utilisateur, mais uniquement pour des opérations spécifiques et sensibles.


Selon vos commentaires, si vous devez l'implémenter vous-même, votre solution n'est pas trop mauvaise, mais je la simplifierais.
Vous pouvez générer un nonce crypto-aléatoire (assez long), le stocker dans la mémoire de la session et le changer toutes les X minutes (vous stockez également le temps d'expiration dans la session). Dans chaque formulaire, vous incluez le nonce dans un champ de formulaire masqué et comparez cette valeur lorsque le formulaire est publié.
Si le jeton de formulaire correspond, vous êtes clair. Sinon, vous pouvez accepter par exemple le jeton précédent également, pour gérer les cas Edge.

Bien que je doive dire que j'ai vu trop de tentatives infructueuses de mise en œuvre par soi-même, pour vraiment recommander cette voie. Vous feriez mieux de trouver un package minimal pour le faire pour vous.

25
AviD

Il y a une bonne explication sur OWASP: OWASP CSRF Prevention Cheat Sheet

En bref, ils disent qu'il y a deux façons:

  1. Ajoutez un jeton aléatoire à chaque session utilisateur. Ce n'est que si ce jeton est présent et correct que les modifications seront appliquées, sinon la demande doit être rejetée. Il est important que le token soit envoyé uniquement avec une POST, car les requêtes GET peuvent divulguer le token à différents endroits (historique du navigateur, fichiers journaux, etc.).

    Il est également possible de générer un jeton par requête, mais cela entraîne des problèmes de convivialité. Par exemple, le bouton de retour ne fonctionnerait plus correctement. Mais bien sûr, la sécurité serait renforcée.

    Assurez-vous également (pour améliorer encore plus la sécurité) que le jeton n'est envoyé que via TLS, il n'y aura donc pas d'homme au milieu des problèmes.

  2. L'autre option consiste à utiliser une sorte de défi - réponse (par exemple CAPTCHA ou jetons uniques).

La page OWASP répertorie également quelques mesures qui ne fonctionnent pas. Ceux-ci sont

  • Utilisation de cookies (secrets)
  • Ne pas utiliser les requêtes GET
  • Transactions en plusieurs étapes
  • Réécriture d'URL
27
Andreas Arnold

En plus de la réponse @Andreas Arnold, il existe une alternative. J'ai implémenté le Encrypted Token Pattern d'OWasp.

Outre la prévention des attaques csrf, il présente l'avantage supplémentaire de mettre en œuvre la sécurité des objets.

Seuls ceux qui sont autorisés à modifier des objets peuvent le faire. D'autres n'auront pas le texte ou la clé de chiffrement correct/valide. Je crypte généralement sessionId, timestamp, userId et/ou recordId.

timestamp empêche replayAttacks. sessionid isole les modifications de cette session uniquement userId isole les modifications de cet utilisateur uniquement. Si vous incluez recordId, alors au prix d'un traitement supplémentaire, vous gagnez en sécurité.

3
Nasir