web-dev-qa-db-fra.com

Démystifier l'authentification Web (cookies de session sans état)

Je recherche actuellement des protocoles d'authentification des utilisateurs pour un site Web que je développe. Je souhaite créer un cookie d'authentification afin que les utilisateurs puissent rester connectés entre les pages.

Voici mon premier bash:

cookie = user_id|expiry_date|HMAC(user_id|expiry_date, k)

k est HMAC(user_id|expiry_date, sk) et sk est une clé de 256 bits connue uniquement du serveur. HMAC est un hachage SHA-256. Notez que "|" est un séparateur, pas seulement une concaténation.

Cela ressemble à ceci dans PHP (Remarque, cette question est indépendante du langage, PHP n'est qu'un exemple)):

$key = hash_hmac('sha256', $user_id . '|' . $expiry_time, SECRET_KEY);
$digest = hash_hmac('sha256', $user_id . '|' . $expiry_time, $key);
$cookie = $user_id . '|' . $expiry_time . '|' . $digest;

Je peux voir qu'il est vulnérable aux attaques de relecture comme indiqué dans Un protocole de cookie sécurisé, mais devrait être résistant aux attaques de volume et à l'épissage cryptographique.

LA QUESTION: Suis-je sur la bonne voie ici, ou y a-t-il une vulnérabilité massive que j'ai ratée? Existe-t-il un moyen de se défendre contre les attaques de relecture qui fonctionne avec des adresses IP attribuées dynamiquement et n'utilise pas de sessions? Je ne veux pas stocker quoi que ce soit côté serveur pour avoir ce travail.

De plus, je ne planifie pas ou ne lance pas le mien. Je demande cela pour mieux juger quelle solution choisir. Donc pas de réponses "Utilisez simplement la solution X" sans une sorte d'explication.

REMARQUES

Le matériel le plus récent que j'ai lu:
À faire et à ne pas faire pour l'authentification des clients sur le Web alias Fu et al.
( https://pdos.csail.mit.edu/papers/webauth:sec10.pdf )

Un protocole de cookie sécurisé alias Liu et al.
( http://www.cse.msu.edu/~alexliu/publications/Cookie/cookie.pdf )
qui développe la méthode précédente

Cookies de session sans état renforcés
( http://www.lightbluetouchpaper.org/2008/05/16/hardened-stateless-session-cookies/ )
qui développe également la méthode précédente.

Comme le sujet est extrêmement compliqué, je ne cherche que des réponses d'experts en sécurité ayant une expérience réelle de la création et de la rupture de schémas d'authentification.

42
Joony

Les "attaques par rejeu" ne s'appliquent pas vraiment aux cookies, car un cookie est par définition quelque chose qui doit être rejoué: le navigateur de l'utilisateur renvoie la même valeur de cookie, et c'est ainsi que votre le serveur sait qu'il s'agit du même utilisateur.

Ce que vous voulez éviter, c'est que quelqu'un espionne la ligne, observe la valeur du cookie, puis envoie le même cookie sur ses propres connexions. La seule solution pratique connue pour cela est d'exécuter l'ensemble du protocole à l'intérieur d'un tunnel qui garantit la confidentialité et l'intégrité des données en transit, et qui est connu sous le nom de "SSL" (aka [[# # ~] https [~ # ~] ).

Il existe ensuite deux façons de générer et de vérifier les valeurs des cookies sur le serveur:

  • Vous pouvez simplement générer une valeur aléatoire de taille suffisante (c'est-à-dire 16 octets environ), de sorte qu'il serait hautement improbable qu'un attaquant devine la valeur par pure chance. Le serveur se souvient pour chaque utilisateur de son "jeton de session" actuel, en tant que colonne supplémentaire dans la base de données "utilisateurs".

  • Vous produisez le jeton comme une valeur infalsifiable déterminée de manière déterministe à partir de l'identifiant utilisateur. C'est ce que vous faites et c'est un concept raisonnable. Fondamentalement, au lieu de stocker un état supplémentaire sur le serveur, vous le déchargez sur le client et vous utilisez un MAC avec une clé côté serveur pour que les clients ne peut pas forger des valeurs de cookies "valides".

Votre code décrit deux appels HMAC imbriqués, ce qui est étrange et injustifié. Un appel suffit. La construction générique est qu'un cookie contient une valeur v et un MAC m tels que v code l'état que vous vouliez à stocker dans le client, et m est calculé sur v. L'état que vous souhaitez stocker, dans votre cas, est: "ce client a un ID utilisateur i et s'est connecté au moment t". Vous pouvez utiliser l'encodage de votre choix à condition de pouvoir le décoder sans ambiguïté.

Pour résumer les choses: la production de valeurs de cookie avec un MAC est un moyen valide de faire la gestion de session, et HMAC/SHA-256 est bon pour cela. Mais vous devez le considérer comme une optimisation: vous stockez des valeurs dans le client pour éviter de les stocker sur le serveur. Cela a la conséquence malheureuse que le client peut oublier des données hors de votre contrôle (le client peut détruire le cookie) ou peut effectuer des déformations de temps (le client peut changer la valeur stockée dans son navigateur en une valeur de cookie plus ancienne - un problème qui est atténuée par l'inclusion de dates dans les cookies, sous le contrôle du MAC).

Si vous pouvez garder le côté serveur d'état et simplement utiliser des valeurs de cookies aléatoires, faites-le: c'est plus simple et donne plus de contrôle au serveur.

35
Thomas Pornin

La première étape de la sécurisation d'une application Web consiste à utiliser SSL. Cela garde votre cookie confidentiel, empêche les attaques de relecture, garantit que l'utilisateur parle au bon serveur, empêche MitM, empêche les attaquants de modifier les données sur le réseau ...

Ensuite, définissez l'indicateur secure sur le cookie, de sorte qu'il ne soit envoyé que via SSL. La définition du drapeau http-only, Pour empêcher javascript de le lire, ne fait pas de mal non plus.

Enfin concernant votre schéma de cookies:

  • Le HMAC imbriqué ne vous rapporte rien. Allez simplement avec user_id|expiry_date|HMAC(user_id|expiry_date, SECRET_KEY)
  • Changez régulièrement SECRET_KEY
  • Le user_id Ne doit jamais changer. c'est-à-dire utiliser l'identifiant utilisateur numérique, pas le nom d'utilisateur ou l'e-mail
  • Ni user_id Ni expiry_date Ne doivent jamais contenir un | Pour assurer une séparation nette des domaines
  • Si vous êtes paranoïaque, utilisez un serveur de connexion spécialisé, qui signe le cookie au lieu de le MACer. Ainsi, le serveur de connexion est le seul serveur disposant de la clé requise pour créer des cookies, les serveurs Web normaux ne peuvent que la valider. => réduit la surface d'attaque
  • Le serveur peut créer des cookies valides pour tout utilisateur. Cela pourrait être indésirable.
13
CodesInChaos

Tout d'abord:

N'inventez pas vos propres protocoles de sécurité. Vous risquez fort de vous tromper.

Maintenant que c'est hors de propos, regardons cela. Si je peux jamais obtenir HMAC(userid|expiry_date, k), sans me connecter ni m'être authentifié en tant qu'utilisateur, j'ai rompu la sécurité de ce système. Cela s'étend à toutes sortes de problèmes, tels que les attaques de fixation de session ou de piratage de session (souvent causées par l'utilisation incorrecte ou incorrecte de SSL/TLS).

Lorsque vous vérifiez le cookie de session, perdez-vous des informations sur les canaux secondaires de synchronisation? Utilisez-vous définitivement HMAC correctement? Vous avez dit que votre HMAC est SHA-256, voulez-vous dire en fait HMAC-SHA-256? Pourquoi passer par une procédure HMAC compliquée, alors que vous pouvez simplement générer une chaîne aléatoire et l'associer à un utilisateur sur le serveur (par exemple dans une base de données)? Pourquoi ne pas simplement utiliser user_id|expiry_date|HMAC-SHA-256(user_id|expiry_date, sk) (où | Est la concaténation, pas le caractère littéral du tube)?

En ce qui concerne la défense contre les attaques par rejeu dans un environnement Web, examinez projet CSRFGuard de l'OWASP . Vous ne pourrez pas l'intégrer directement, mais il peut y avoir un PHP équivalent quelque part. Tout est théorique si votre site est vulnérable aux attaques XSS, cependant.

La sécurité devrait être transférée à un cadre respecté et testé au combat, et non pas fait ad-hoc

Edit, un bref mot sur les attaques de fixation de session:

J'ai supposé que si vous ne confiez pas la sécurité à un framework bien testé, vous êtes probablement vulnérable. Vous devrez essentiellement vérifier que vous émettez une clé de session distincte lorsque l'utilisateur s'authentifie (c'est-à-dire différente de celle avec laquelle l'utilisateur a commencé). Avec la stratégie ci-dessus, user_id|expiry_date|HMAC(user_id|expiry_date, k) ne changerait pas lorsque l'utilisateur s'authentifierait, le laissant vulnérable à une attaque de fixation de session.

8
Tinned_Tuna

Comme le sujet est extrêmement compliqué, je ne cherche que des réponses d'experts en sécurité ayant une expérience réelle de la création et de la rupture de schémas d'authentification.

Vous avez raison de dire que le sujet est extrêmement compliqué.

Allez avec les fonctions de session fournies par votre framework et n'essayez pas de rouler les vôtres. Si vous utilisez plain PHP au lieu d'un framework ... shudders.

3
user10211