web-dev-qa-db-fra.com

Comment implémenter la fonctionnalité «mot de passe oublié»?

Pour mon projet, j'ai besoin d'une fonctionnalité " mot de passe oublié".

Je ne sais pas encore comment implémenter ce type de fonctionnalité, alors j'espérais trouver des "meilleures pratiques" sur Internet, mais je n'ai rien trouvé d'utile qui traite tous les aspects importants de cette fonctionnalité assez courante.


Mes propres réflexions à ce sujet sont assez simples:

Si un utilisateur voulait changer son mot de passe, je pouvais créer un jeton unique uniqueTokenForTheUser attaché à une "demande de changement de mot de passe" qui serait essentiellement l'identifiant de mon backend pour dire si c'était le bon utilisateur qui avait envoyé la demande.

Par exemple, je générerais/enverrais un e-mail à [email protected] avec un lien

http://www.example.com/changePassword?token=uniqueTokenForTheUser

uniqueTokenForTheUser serait stocké dans une table qui est vérifiée par un thread dans un certain intervalle et supprime l'enregistrement une fois le jeton expiré au cas où l'utilisateur n'aurait pas réellement changé son mot de passe.

Bien que cela me semble assez simple, je voulais vérifier s'il y avait des "meilleures pratiques", par exemple en ce qui concerne la génération et la suppression de ce jeton particulier.

Toutes suggestions ou références à des articles/tutoriels sont les bienvenues!


Liens supplémentaires suggérés par les commentaires:

71
displayname

Utilisez HTTPS uniquement pour cela, puis nous verrons les détails de la mise en œuvre.

Tout d'abord, vous allez vouloir vous protéger contre énumération des utilisateurs .

Autrement dit, ne révélez pas dans la page si l'utilisateur existe ou non. Cela ne doit être divulgué que dans l'e-mail lui-même.

Deuxièmement, vous voudrez éviter fuite de référent . Assurez-vous qu'aucun lien externe ou ressource externe n'est présent sur votre lien cible. Une façon d'atténuer cela est de rediriger une fois le lien initial suivi afin que le jeton ne soit plus dans la chaîne de requête. Sachez que si quelque chose ne va pas (par exemple, votre base de données est brièvement en panne) et qu'un modèle d'erreur standard est affiché, cela peut entraîner une fuite du jeton s'il contient des références externes.

Générez un jeton avec 128 bits d'entropie avec un CSPRNG. Stockez ce côté serveur à l'aide de SHA-2 pour empêcher toute vulnérabilité de fuite de données sur votre table de réinitialisation de permettre à un attaquant de réinitialiser les mots de passe. Notez que le sel n'est pas nécessaire. Expirez ces jetons après un court laps de temps (par exemple quelques heures).

En plus de fournir le jeton non haché à l'utilisateur dans le lien de courrier électronique, donnez à l'utilisateur la possibilité d'accéder à la page manuellement, puis collez la valeur du jeton. Cela peut empêcher les valeurs de chaîne de requête d'être enregistrées dans l'historique du navigateur et dans les journaux de proxy et de serveur par défaut.

Vous pouvez éventuellement vous assurer que l'identifiant de session pour la session qui a lancé la réinitialisation du mot de passe est celui qui a suivi le lien . Cela peut aider à protéger un compte où l'attaquant a accès au courrier électronique de l'utilisateur (par exemple, en configurant une règle d'avance rapide avec un accès limité au compte de messagerie). Cependant, tout cela empêche vraiment un attaquant de suivre de manière opportuniste une réinitialisation demandée par l'utilisateur - l'attaquant pourrait toujours demander son propre jeton de réinitialisation pour la victime s'il souhaite cibler votre site particulier.

Une fois que le mot de passe a été réinitialisé sur celui de l'utilisateur, vous devrez expirer le jeton et envoyer à l'utilisateur un e-mail pour lui faire savoir que cela s'est produit juste au cas où un attaquant aurait réussi à réinitialiser son mot de passe (sans nécessairement avoir le contrôle). de leur compte mail) - défense en profondeur. Vous devez également faire pivoter l'identifiant de session en cours et expirer tous les autres pour ce compte d'utilisateur . Cela supprime la nécessité pour l'utilisateur de se reconnecter, tout en effaçant toutes les sessions montées par un attaquant, bien que certains utilisateurs aiment que le site les déconnecte afin d'obtenir une confirmation de confirmation que leur mot de passe a bien été réinitialisé. La redirection vers la page de connexion donne également à certains gestionnaires de mots de passe la possibilité d'enregistrer l'URL de connexion et le nouveau mot de passe, bien que beaucoup détectent déjà le nouveau mot de passe à partir de la page de réinitialisation.

Vous pouvez également envisager d'autres options hors bande pour le mécanisme de réinitialisation et les notifications de modification. Par exemple, par SMS ou alertes par téléphone mobile.

69
SilverlightFox

Votre ligne de pensée est sur la bonne voie. Cependant, je suggère de décrire le flux de votre fonctionnalité de mot de passe oublié à partir d'une étape précédente. Quelqu'un prétend avoir oublié son mot de passe, vous devez vous assurer que vous identifiez que cette personne est bien le propriétaire du compte pour lequel vous allez démarrer le mot de passe procédure de récupération.

Le flux ci-dessous suppose un service où les gens peuvent s'inscrire, comme un site Web (en d'autres termes, une liste d'e-mails enregistrés et/ou de noms d'utilisateur peut être créée à l'aide de la fonctionnalité d'inscription).

première étape: identifier l'utilisateur

  1. En cliquant sur le lien "Oups, j'ai oublié mon mot de passe", présentez à l'utilisateur un formulaire dans lequel il saisit son nom d'utilisateur et son adresse e-mail (éventuellement, donnez-lui un indice sur l'adresse e-mail sous la forme: 's ..... @ o .... com ');
  2. les informer si l'adresse e-mail qu'ils ont saisie appartient au nom d'utilisateur qu'ils ont entré (oui ou non);
  3. Si le nom d'utilisateur et le mot de passe saisis correspondent, passez aux étapes suivantes.

étape deux: démarrer la procédure de récupération

  1. générer un jeton de récupération aléatoire (128 bits devraient suffire);
  2. stocker un hachage de ce jeton (créé à l'aide d'un algorithme de hachage de mot de passe), ainsi que son horodatage de création dans votre base de données;
  3. envoyer à l'utilisateur un e-mail avec un lien (contenant le jeton de récupération) vers un formulaire de changement de mot de passe. L'URL du formulaire de changement de mot de passe doit être HTTPS.
  4. lorsque vous recevez la demande de changement de mot de passe, vous cochez: [1]. la validité du jeton (en utilisant son temps de création par rapport à l'heure actuelle, une fenêtre de temps de 10 minutes devrait généralement suffire); [2]. si le jeton présenté est correct (hachez le jeton, comparez le hachage résultant à celui de votre base de données, comme vous le feriez pour un mot de passe);
  5. si tous les contrôles réussissent, passez à l'étape suivante.

Étape 3: mettre à jour leur mot de passe

  1. détruisez toutes les informations "souvenez-vous de moi" que vous avez peut-être stockées pour cet utilisateur;
  2. détruire toutes les sessions actives associées à cet utilisateur;
  3. mettre à jour le mot de passe de l'utilisateur;
  4. envoyer éventuellement un e-mail à leur adresse e-mail pour les informer de la modification;
  5. connectez l'utilisateur.
13
Jacco

Vous êtes proche de la meilleure pratique avec votre approche. Un petit ajout serait:

  • Vous pouvez exiger que le nom d'utilisateur corresponde au jeton plutôt que de simplement déduire l'utilisateur du jeton.

  • Vous devriez plutôt utiliser https que http.

Les autres questions:

  • En ce qui concerne la génération: une façon habituelle de les générer est d'utiliser des UUID, mais comme le soulignent les commentaires, vous devriez plutôt utiliser une chaîne complètement aléatoire et suffisamment longue.

  • En ce qui concerne la suppression: vous pouvez nettoyer régulièrement les anciens jetons inutilisés comme vous l'avez suggéré. Utilisez peut-être un délai qui permet au courrier de passer par la liste d'e-mails habituelle, par ex. 15 minutes.

7
Tobi Nary

Quelques réflexions à ce sujet:

  • Le courrier électronique est intrinsèquement non sécurisé. Le jeton pourrait être volé n'importe où entre votre serveur et la boîte de réception des utilisateurs par un attaquant. Envisagez d'utiliser un autre moyen de communication si possible, comme les SMS.
  • Si vous allez par e-mail, le lien de restauration doit être via HTTPS, pas HTTP. Au moins cette partie du processus peut être cryptée.
  • Pour éviter les attaques d'énumération des utilisateurs, vous souhaiterez peut-être afficher le même message plus ou moins le nom d'utilisateur/adresse e-mail que l'utilisateur saisit existe ou non. (Au moins, ne faites pas l'erreur d'afficher l'e-mail après que l'utilisateur a entré uniquement le nom d'utilisateur.)
  • Utilisez un bon générateur de nombres pseudo-aléatoires et un long jeton. Personne ne devrait pouvoir deviner le jeton. Pour rendre la devinette du jeton plus difficile, exigez que l'utilisateur entre à la fois le nom d'utilisateur et le jeton. La limitation du nombre de tentatives (par nom d'utilisateur et/ou IP) empêchera également le forçage brutal. Peut-être aussi un CAPTCHA?
  • Vous souhaitez limiter la durée de validité d'un jeton. L'e-mail peut être lent s'il reste bloqué dans les filtres, mais je ne vois aucune raison pour laquelle quelqu'un aurait besoin de plus que de dire une demi-heure.
  • Une fois un compte restauré, mettez fin à toutes les anciennes sessions de ce compte. L'utilisateur peut vouloir restaurer le compte car il a été compromis, puis l'attaquant doit être déconnecté.
  • N'envoyez qu'un jeton à usage unique et pas un nouveau mot de passe! Les mots de passe ne doivent jamais être envoyés par e-mail.
  • Ne permettez à un jeton d'être utilisé qu'une seule fois! Supprimez-le immédiatement après son utilisation (même si l'utilisateur ne change pas réellement le mot de passe).

Pour plus de lecture sur le sujet, je recommande Troy Hunt .

4
Anders