Une réinitialisation de mot de passe est une connexion qui saute l'étape du mot de passe : chaque contrôle du formulaire de connexion doit donc y être reproduit ou délibérément remplacé. Si le chemin de réinitialisation est plus faible que celui de la connexion, un attaquant l'empruntera. L'OWASP Forgot Password Cheat Sheet qualifie cette fonction de « source courante de vulnérabilités », l'énumération d'utilisateurs en étant l'exemple le plus connu.
Pourquoi le parcours de réinitialisation est le maillon faible
Une connexion réussie produit une session. Selon les recommandations OWASP sur la gestion des sessions, l'identifiant d'une session authentifiée équivaut temporairement à la méthode d'authentification la plus forte utilisée par l'application. Une réinitialisation qui aboutit à une session, ou à un mot de passe choisi par l'attaquant, donne accès à la même chose.
Le NIST SP 800-63B-4 exige, au niveau AAL2, la preuve de possession et de contrôle de deux facteurs d'authentification distincts. Si la connexion demande deux facteurs, une réinitialisation qui n'exige qu'un jeton envoyé par e-mail est un contournement à facteur unique. L'extrait sur lequel nous nous appuyons ne couvre pas la récupération de compte ; le document complet contient une section sur la gestion des événements liés aux authentificateurs.
Notre règle : sur un compte disposant d'un second facteur enrôlé, demandez ce facteur ou un code de récupération enregistré avant d'accepter le nouveau mot de passe, et ne laissez jamais une réinitialisation supprimer ou remplacer le facteur.
L'étape de demande
Répondez de manière identique, que le compte existe ou non. « Si cette adresse est enregistrée, nous avons envoyé un e-mail » suffit.
Le temps de réponse fuit aussi. Un traitement qui s'interrompt tôt pour les adresses inconnues et envoie un e-mail pour les adresses connues révèle la différence, quel que soit le message affiché. Exécutez la même logique pour chaque requête, ou confiez l'envoi du mail à une tâche asynchrone.
Ajoutez une limitation du nombre de requêtes par compte (rate limiting), un CAPTCHA ou un contrôle similaire. Sans cela, un attaquant peut envoyer des milliers de demandes de réinitialisation par heure vers un même compte et noyer la boîte e-mail ou les SMS de la victime. Ne verrouillez ni ne modifiez le compte du seul fait d'une demande.
Le jeton
L'OWASP attend quatre choses d'un jeton ou d'un code :
- il est généré avec un algorithme aléatoire cryptographiquement sûr ;
- il est assez long pour résister à la force brute ;
- il est stocké de façon sécurisée ;
- il est à usage unique et expire après une durée appropriée.
La fiche ne donne aucun chiffre pour la longueur ni pour la durée de vie. La valeur la plus proche dans les sources figure dans les recommandations sur les sessions : un CSPRNG avec au moins 128 bits d'entropie, 160 bits ou plus de préférence. Elle est écrite pour les jetons de session ; nous l'appliquons aux jetons de réinitialisation. Pour la durée de vie, choisissez une valeur courte, documentez-la et testez-la.
« Stocké de façon sécurisée » peut se lire strictement. Si la divulgation en lecture seule du stockage des jetons fait partie de votre modèle de menace, les recommandations sur les sessions décrivent une séparation entre un identifiant et un vérificateur secret. Le serveur conserve l'identifiant public de recherche et le hash SHA-256 complet du vérificateur, et compare les hashes en temps constant. L'identifiant seul ne doit jamais valoir preuve. Appliquer ce principe aux jetons de réinitialisation est une suggestion de notre part.
Transmettez le jeton par un canal séparé, e-mail ou SMS, jamais dans la réponse du navigateur. Placer le jeton dans l'URL est la conception la plus simple, mais les recommandations sur les sessions avertissent que les identifiants présents dans les URL peuvent fuiter via les liens et les journaux, l'historique du navigateur et les favoris, l'en-tête Referer et les moteurs de recherche. Exclure de la page de réinitialisation tout contenu tiers et tout lien sortant ne referme que la fuite par Referer. Pour le reste, échangez le jeton dès la première requête contre un état côté serveur de courte durée, redirigez vers une URL propre, et gardez cette première query string hors des journaux d'accès.
L'étape de réinitialisation
- Faites saisir deux fois le nouveau mot de passe et vérifiez-le selon la même politique que lors de l'inscription.
- Hachez-le via le même code que tous les autres mots de passe.
- Invalidez tous les jetons de réinitialisation en cours pour le compte lorsque le mot de passe ou l'adresse e-mail change. Sinon, un ancien message resté dans une boîte de réception peut réinitialiser de nouveau le compte.
- Envoyez un e-mail à l'utilisateur pour l'informer du changement de mot de passe. Ne mettez jamais le mot de passe dans le message.
- Renvoyez l'utilisateur vers la connexion normale au lieu de l'authentifier directement. La connexion automatique ajoute du code de gestion de session, et avec lui le risque de nouvelles vulnérabilités.
- Mettez fin aux sessions existantes, ou au moins proposez de le faire.
Après une compromission présumée, la session active de l'attaquant survit à un changement de mot de passe si vous n'y mettez pas fin. Nous ferions de l'invalidation le comportement par défaut.
MFA et comptes compromis
Une réinitialisation de mot de passe ne suffit pas toujours à reprendre le contrôle. L'attaquant peut encore détenir une session active, ou avoir modifié les informations de récupération ou les méthodes MFA.
L'OWASP recommande de ne pas se fier uniquement à des informations de récupération récemment ajoutées ou modifiées. Utilisez des preuves indépendantes établies auparavant, comme des codes de récupération enregistrés, dans une combinaison qui satisfait aux exigences d'assurance du compte. La réinitialisation de la MFA a sa propre section dans l'OWASP Multifactor Authentication Cheat Sheet : gardez donc ce processus séparé du parcours de mot de passe.
L'OWASP Authentication Cheat Sheet traite également du changement d'adresse e-mail enregistrée, ce qui compte, car une adresse modifiée redirige toutes les réinitialisations futures.
Tester le parcours
| Test | Résultat attendu |
|---|---|
| Adresse existante et adresse inexistante | Même message et même code de statut |
| Lot scripté de requêtes par adresse | Temps de réponse médians identiques |
| Demandes répétées pour un même compte | Le rate limiting ou le CAPTCHA se déclenche |
| Demande de réinitialisation, puis connexion | Compte ni verrouillé ni modifié |
| Jeton utilisé deux fois, ou après expiration | La tentative échoue |
| Ancien jeton après changement de mot de passe ou d'e-mail | La tentative échoue |
| Page de réinitialisation avec le jeton dans l'URL | Aucune requête tierce, aucun lien sortant |
| Réinitialisation avec une ancienne session ouverte | Ancienne session terminée |
| Second facteur enrôlé, jeton e-mail seul (notre règle) | Réinitialisation refusée |
| Réponse finale et e-mail | Pas de connexion automatique, pas de mot de passe dans le mail |
Pour la ligne sur le temps de réponse, comparez les médianes et la dispersion sur de nombreuses exécutions. Ce test a sa place dans tout test d'intrusion d'un parcours d'authentification.
Par où commencer
- Demandez de nombreuses fois une réinitialisation pour un compte existant et pour un compte inexistant. Comparez le message, le code de statut et le temps de réponse.
- Lisez le générateur de jetons. Vérifiez qu'il utilise un CSPRNG, rendez les jetons à usage unique et fixez une durée de vie que vous pouvez exprimer en minutes.
- Ajoutez une limitation du nombre de requêtes par compte ou un CAPTCHA au point d'entrée de la demande, et vérifiez qu'une demande ne verrouille ni ne modifie jamais le compte.
- Faites en sorte que la réinitialisation mette fin aux autres sessions, invalide les jetons en cours et envoie un e-mail de notification sans le mot de passe. Vérifiez que la page de réinitialisation ne charge rien depuis des tiers.
- Prenez un compte de test avec la MFA activée et essayez de le réinitialiser uniquement avec le jeton reçu par e-mail. Vérifiez que la réinitialisation est refusée.
- Vérifiez qui peut réinitialiser ou supprimer un second facteur, quelles preuves cette personne doit présenter, et si la récupération traite les informations récemment modifiées comme non fiables.
