Question:
Les mots de passe doivent-ils être réinitialisés automatiquement lorsque la méthode sous-jacente change
Crazy Dino
2016-03-21 19:03:57 UTC
view on stackexchange narkive permalink

Je suis actuellement ingénieur sur un projet en phase de développement. Un «module» sur ce projet donne la possibilité d'authentification / autorisation des utilisateurs. Cependant, il est venu à notre préoccupation que l'algorithme de hachage de mot de passe peut ne pas être à la hauteur (c'est-à-dire pas BCrypt). (La chose terrible n'est pas tout à fait sûr de ce que c'est et d'où il vient!).

Cela doit évidemment changer et le patch est en cours de planification. Nous devons naturellement mettre à jour tous nos utilisateurs de test car leurs mots de passe utiliseront l'ancienne méthode de hachage, ce qui ne pose pas vraiment de problème, tous nos utilisateurs de démonstration sont automatisés lors de la construction, donc il met à jour le script. Mais la question suivante est de savoir si c'était un système de production avec des utilisateurs actifs et obsolètes, de toutes quantités. Quelle serait la meilleure pratique.

  1. Forcer automatiquement la réinitialisation du mot de passe pour chaque utilisateur? Cela informera chaque utilisateur que son mot de passe a été modifié et peut causer des questions / confusion et peut faire suspecter une faille de sécurité. D'autres questions peuvent être posées auxquelles les parties prenantes du site Web ne pourront pas nécessairement répondre.
  2. Mettez à jour la base de données pour indiquer s'il s'agit de la nouvelle ou de l'ancienne méthode, puis une fois qu'un utilisateur a été authentifié, mettez à jour son mot de passe dans le DB utilisant. Nécessite un peu de logique dans le service et la transition ne semblera pas à tout utilisateur existant. Le problème étant qu'il y avait une brèche, alors il peut être évident qu'il y a deux méthodes en cours ici et si la moins sécurisée s'avère aussi peu sûre, elle pourrait évidemment être cassée.
  3. Réinitialiser tous les mots de passe, en utilisant une version BCrypted du hachage existant. Marquez-le comme l'ancien style, donc en cas d'authentification réussie, il conserve simplement un hachage du mot de passe plutôt qu'un hachage d'un hachage.
Il y a un vote pour "principalement basé sur l'opinion", ce que je ne suis pas d'accord: il y a des choses solides et objectives à dire ici.
L'ancien algorithme est-il réversible? Ignorer les problèmes éthiques pendant un moment; si l'ancien algorithme est cassé et suffisamment compréhensible pour vous permettre de récupérer les mots de passe d'origine, il serait alors possible de mettre à jour les enregistrements utilisateur avec le nouvel algorithme sans que les utilisateurs se connectent, et ils n'en seraient pas plus sages. Juste une pensée!
@GreatSeaSpider Même s'ils utilisaient MD5 non salé, il faudrait des mois de temps de calcul pour déchiffrer le mot de passe de tout le monde - peut-être plusieurs mois si vous avez des utilisateurs utilisant des mots de passe aléatoires de 32 caractères. Cela représente beaucoup de dollars en serveurs et en électricité. Certainement moins cher de faire quelque chose comme 2. ou 3.
Sur une inspection plus approfondie. Il semble utiliser PBKDF2 ce qui semble parfaitement acceptable (le développeur en question achète encore des gâteaux pour le reste de la semaine car ce n'était pas évident!). Je pense toujours que l'essentiel de ma question «que faire lors de la modification des hachages de stockage de mots de passe» est valable pour référence future pour d'autres utilisateurs.
Penser à voix haute: serait-il judicieux de définir une fenêtre de transition? Définissez une heure dans le futur (date de fin du support) après laquelle chaque mot de passe stocké avec l'ancien schéma serait réinitialisé et activez une logique de connexion dans laquelle, si l'utilisateur se connecte correctement, le mot de passe est stocké avec le nouveau hachage (qui manière, vous vous assurez qu'un utilisateur authentifié utilise le système et que seuls les utilisateurs qui ne se connectent pas du tout à la date _fin du support_ verront leur mot de passe réinitialisé). Et le drapeau _old style_ pourrait avoir disparu à la _fin de la date de support_.
@MikeOunsworth Je suis tout à fait d'accord, j'ai vu dans le passé des méthodes de protection des mots de passe faciles à inverser, j'aurais dû être plus clair et dire réversible et trivial (peu coûteux) de le faire.
Pour le n ° 3, je suppose que vous vouliez dire "Rehash all passwords" au lieu de "Reset all passwords" ....
L'option 3 est la meilleure - si elle est correctement mise en œuvre. Mais comme le montre [cette ancienne réponse] (http://security.stackexchange.com/a/103403/47143), il est facile d'introduire des vulnérabilités subtiles mais très graves. L'option 2 est plus facile à faire et pas trop mauvaise.
Pourquoi voulez-vous aussi utiliser `bcrypt`? De nos jours, vous devriez utiliser `argon2`, qui a remporté le concours de hachage de mot de passe ...
@wb9688 Je n'utiliserais pas encore de l'argon2, trop nouveau à mon goût. Je préfère bcrypt ou scrypt.
Six réponses:
Mike Ounsworth
2016-03-21 19:14:27 UTC
view on stackexchange narkive permalink

Votre option 1. est une mauvaise idée: en plus des raisons d'expérience utilisateur / relations publiques que vous indiquez, vous donnez également aux attaquants une fenêtre pour intercepter les jetons de réinitialisation de mot de passe et compromettre chaque compte sur votre serveur. Cela ne résout pas non plus votre problème si vous avez même un utilisateur qui est trop paresseux pour se connecter / mettre à jour son mot de passe.

À première vue, les 2. et 3. me semblent bien. Votre n ° 2 n'est pas moins sécurisé que ce que vous faites actuellement, mais 2. signifierait que vous devez continuer à supporter la connexion faible actuelle pour toujours (ou faire quelque chose comme "Après X mois, nous effaçons votre mot de passe et vous oblige à le faire une restauration "qui brise la belle transparence utilisateur que vous voulez, alors ignorons cela).

Considérons le cas où vous avez des utilisateurs dans la base de données qui ne se connecteront plus jamais. Avec les deux 2. et 3. vous devez continuer à prendre en charge l'algue de hachage actuelle dans votre base de code pour toujours juste au cas où ils se connecteraient, mais au moins 3. a l'avantage qu'ils (ou plutôt, vous) êtes protégés contre des attaques par force brute hors ligne si votre base de données est volée.

Puisque vous devrez conserver la colonne "drapeau à l'ancienne" pour toujours, rendez-vous service et faites-en un int pas un booléen de sorte que si jamais vous devez mettre à jour à nouveau votre alg de hachage de mot de passe, vous pouvez enregistrer quel ancien style ils utilisent.


MISE À JOUR: Une question très similaire a été posée ici et est basée sur la discussion de ce fil de discussion.

+1 pour votre dernier paragraphe. Je me suis retiré de cela dans ma réponse.
Le dernier paragraphe vaut une prime. Non pas que je puisse en donner un, alors au lieu de points Internet virtuels, ayez mes sentiments.
"Prenons le cas où vous avez des utilisateurs dans la base de données qui ne se connecteront plus jamais." - bien que dans de nombreux cas, cela soit couvert par une autre pratique recommandée: ce compte serait de toute façon verrouillé après un certain temps afin que vous puissiez abandonner la prise en charge de l'ancien algorithme après cette période.
Vous n'êtes pas obligé de conserver indéfiniment l'ancien algorithme - si un utilisateur ne se connecte pas pendant 12 mois, il n'y a rien à lui demander de réinitialiser son mot de passe ... il y a de bonnes chances qu'il l'ait déjà oublié
@Mindwin: Bien sûr, vous pouvez donner une prime, n'hésitez pas.
@SilverlightFox au moment de la publication, je ne pouvais pas, mais j'ai posé une question bien reçue et j'ai obtenu quelques points virtuels.Mais je pense que je vais travailler les cordes avant de commencer à jouer avec des outils aussi haut de gamme.XD
TTT
2016-03-21 20:10:40 UTC
view on stackexchange narkive permalink

Si vous pouvez faire l'option 3, je ne vois pas pourquoi vous envisageriez même les autres. C'est de loin la meilleure option. Avec cette option, mon instinct serait d'envisager d'utiliser deux sels différents, un pour l'ancien algorithme et un pour le nouveau avec bcrypt. J'envisage une configuration comme celle-ci:

  1. Configurez votre nouveau système de mot de passe comme vous le feriez si vous commenciez aujourd'hui.
  2. Créez une nouvelle table séparée contenant des champs pour le nom d'utilisateur (ou id), l'algorithme de hachage (nom ou id), salt.
  3. Lors de la connexion, vérifiez si l'utilisateur a un enregistrement dans la table séparée, et si oui, hachez le mot de passe à l'ancienne, puis hachez le résultat de la nouvelle manière et comparez-le avec le hachage bcrypt. S'il correspond, re-salt / hachez le mot de passe de la nouvelle manière et supprimez l'enregistrement de la table séparée.

L'inconvénient est que vous devrez garder le mot de passe en mémoire quelques millisecondes de plus (peu importe) et vous aurez la recherche de table supplémentaire à chaque connexion, à peu près pour toujours, jusqu'à ce que la table séparée soit vide ou jusqu'à ce que les anciens comptes deviennent suffisamment obsolètes pour que vous soyez prêt à leur demander de réinitialiser leur mot de passe eux-mêmes.

"en utilisant deux sels"? Il devrait y en avoir un pour chaque enregistrement de la base de données; salt ne doit pas être partagé par tous les enregistrements utilisant le même schéma de hachage.
@BenVoigt - Bien sûr. Je parlais de ne pas utiliser le même sel (par utilisateur) pour l'ancien hachage et le nouveau hachage.
@TTT: N'est-ce pas hors de propos? Vous n'avez qu'un seul hachage à tout moment dans le schéma de l'OP (ancien hachage du mot de passe, nouveau hachage de l'ancien hachage du mot de passe ou nouveau hachage du mot de passe) donc vous n'avez pas besoin de plus d'un sel de toute façon.
@MatthieuM. - Probablement oui. C'est en fait pourquoi je l'ai appelé un "sentiment instinctif". Il est basé sur la théorie selon laquelle le double hachage avec différents algorithmes peut réduire l'entropie. Je pense que j'extrapolais là-dessus et je me demandais si l'ancien algorithme était en quelque sorte lié au nouveau, le partage du sel pourrait-il en quelque sorte fournir des informations supplémentaires? Nous faisons: F2 (salt2, F1 (salt1, pass)). Pour une fonction inconnue 1, si salt1 = salt2 y a-t-il quand même plus d'informations? Probablement pas, mais je ne sais pas comment le prouver définitivement, d'où mon "instinct".
AMADANON Inc.
2016-03-22 06:01:40 UTC
view on stackexchange narkive permalink

Notez que, si votre ANCIEN schéma est haché avec du sel, vous ne pourrez pas utiliser le schéma n ° 3, sauf si vous stockez le sel SÉPARÉMENT.

Normalement, le sel est stocké avec le hachage, et vous utilisez le sel comme entrée de la fonction de hachage - si vous n'utilisez pas exactement le même sel, vous obtiendrez une sortie complètement différente.

Si vous newhash (oldsalt + oldhash, newsalt), alors, même avec le mot de passe correct, vous ne pourrez pas recréer oldhash (puisque vous n'avez pas oldsalt), et vous ne pourrez pas générer le hachage final. La même chose s'applique à tout ce qui a des paramètres (par exemple, bcrypt a un paramètre "cost" - il doit être défini lors du chiffrement, et est intégré dans la sortie, pour être utilisé lors de la validation du mot de passe).

AUSSI : comme cela a été mentionné par d'autres, si vous stockez que le hachage est de style "ancien" ou "nouveau", envisagez plutôt de stocker le "schéma" - où, par exemple 0 est le "vieux", et 1 est bcrypt (notez que je n'utilise pas "nouveau" - il est "nouveau" maintenant, ne sera pas "nouveau" pour toujours!). Une manière courante de faire ceci est d'avoir un marqueur au début du hachage (c'est peut-être déjà le cas!). bcrypt utilise l'un des préfixes standard suivants: "$ 2a $", "$ 2b $", "$ 2x" ou "$ 2y $". Selon les sorties possibles de votre "ancien" algorithme, vous devrez peut-être créer votre propre préfixe pour les marquer, ou vous pourrez peut-être vous en tirer avec 'tout ce qui ne commence pas par' $ 'est l'ancien algorithme.

Et enfin, comme vous êtes manifestement préoccupé (à juste titre!) par la sécurité des anciens mots de passe, je suggère de forcer tout le monde à changer de mot de passe, en leur envoyant des instructions avec un jeton (NE PAS! ENVOYER UN LIEN! Vous ne voulez pas que vos utilisateurs cliquent sur un lien! Dites-leur simplement de se connecter à l'endroit habituel). Ensuite, demandez le jeton ET leur mot de passe. Sinon, quelqu'un qui a volé un mot de passe dans le passé peut changer le mot de passe et obtenir un «nouveau» mot de passe valide.

ENFIN: avoir une date d'expiration - si les mots de passe ne sont pas modifiés à cette date, ils devraient être invalidés. Cette date doit figurer dans l'e-mail, et pas trop loin dans le futur (une semaine? Dépend du temps que mettent vos clients pour répondre). Après cela, ils devront suivre les procédures de «réinitialisation du mot de passe».

Serge Ballesta
2016-03-22 21:30:16 UTC
view on stackexchange narkive permalink

Je ne sais pas quel est votre schéma d'encodage de mot de passe, mais si ce n'est pas trop mal, il est probable que la structure du mot de passe dans l'ancien et le nouveau format soit différente.

J'ai déjà vu quelque chose comme cela dans un ancien système BSD lorsque le système est passé d'un encodage de mot de passe traditionnel à un encodage plus sécurisé. Le nouveau a commencé avec une séquence de caractères qui ne pouvait pas exister dans l'ancien schéma, donc chaque fois qu'un utilisateur avec un ancien mot de passe se connectait, son mot de passe en texte clair était validé à l'aide de l'ancienne méthode et retravaillé silencieusement et stocké dans la base de données de mots de passe la nouvelle méthode. Au bout d'un mois, aucun ancien mot de passe n'était présent dans la base de données, sans que l'utilisateur final ne remarque quoi que ce soit.

Ce serait quelque part entre votre deuxième et troisième méthode.

Je sais que dans un vrai système Web de production, les choses peuvent maintenant être bien pires, car les utilisateurs peuvent attendre des semaines voire des mois avant de se reconnecter. Mais (en fonction de l'activité réelle) cela peut être atténué par le fait qu'un utilisateur qui ne s'est pas connecté depuis plusieurs mois peut avoir oublié son mot de passe - ou vous pouvez lui dire qu'il l'a fait ... Cela signifie que j'attendrais un peu plus longtemps ici probablement 3 ou 6 mois et après cette période, je réinitialiserais tous les anciens mots de passe à une valeur interdite, forçant l'utilisateur à réinitialiser son mot de passe lors de la prochaine connexion ... via l'écran mot de passe oublié .

Les bonnes choses ici sont:

  • transparent pour les utilisateurs normaux
  • aucun changement de schéma de base de données - à condition que le champ du mot de passe puisse accepter les deux styles
  • les utilisateurs occasionnels seront simplement traités comme s'ils avaient oublié leur mot de passe après des mois sans l'utiliser

L'inconvénient est que cela vous oblige à implémenter simultanément les deux méthodes d'authentification + une mise à jour automatique de tous mot de passe de style.

Eric
2016-03-22 04:07:25 UTC
view on stackexchange narkive permalink

Vous n'avez pas mentionné la langue que vous utilisez. Php a ses problèmes avec diverses fonctions qui devraient retourner false alors qu'il devrait retourner true dans certains cas, ou d'autres fonctions qui semblent faire le travail mais manquent de logique pour gérer toutes les entrées possibles valides possibles.

Mais c'est la bonne façon de faire ce dont vous parlez en php même si vous n'utilisez pas php. Le code de haut niveau peut vous laisser un point de départ pour le coder à vos fins.

http://php.net/manual/en/function.password-needs-rehash.php

  $ password = 'rasmuslerdorf'; $ hash = '$ 2y $ 10 $ YCFsG6elYca568hBi2pZ0.3LDL5wjgxct1N8w / oLR / jfHsiQwCqTS'; // Le paramètre de coût peut changer avec le temps à mesure que le matériel s'améliore $ options = array ('cost' = > 11); // Vérifier le hachage stocké par rapport au mot de passe en texte brutif (password_verify ($ password, $ hash)) {// Vérifier si un algorithme de hachage plus récent est disponible // ou si le coût a changé if (password_needs_rehash ($ hash, PASSWORD_DEFAULT, $ options)) {// Si tel est le cas, créez un nouveau hachage et remplacez l'ancien $ newHash = password_hash ($ password, PASSWORD_DEFAULT, $ options); } // Connectez l'utilisateur}  

Ce que je ferais serait votre # 2 avec ce qui a été mentionné en utilisant un int. Après avoir lu la documentation sur PASSWORD_DEFAULT, cela pourrait changer lorsque de meilleurs algorithmes sont trouvés et qu'ils doivent supprimer l'actuel pour des raisons d'insécurité au fur et à mesure que php est mis à jour.

J'ai volontairement gardé ma question indépendante du langage car l'implémentation n'a pas d'importance. Je refuse de toucher php mais d'autres peuvent trouver cela utile à l'avenir?
Micheal Johnson
2016-03-21 21:01:15 UTC
view on stackexchange narkive permalink

Informez les utilisateurs des failles de sécurité de l'ancien système d'authentification et suggérez-leur de changer / réinitialiser leur mot de passe afin d'utiliser le nouveau système d'authentification. Si, après une période prédéterminée (dont les utilisateurs peuvent être informés dans les «petits caractères» quelque part), certains utilisateurs n'ont toujours pas changé / réinitialisé leur mot de passe, désactivez leur compte et envoyez-leur un e-mail les expliquant comment activez-le à nouveau. De cette façon, vos utilisateurs réguliers auront l'impression qu'on leur "demande" de changer leur mot de passe, pas "on leur dit" de changer leur mot de passe, il est donc peu probable qu'ils réagissent négativement à la demande même s'ils changent leur mot de passe (ce qui, espérons , si votre e-mail de conseil est suffisamment convaincant) et vous n'aurez pas à supporter à jamais l'ancien système d'authentification pour les quelques utilisateurs qui n'ont jamais réussi à changer leur mot de passe.

Je ne suis pas d'accord avec ce conseil, principalement à cause des inconvénients déjà signalés par OP en ce qui concerne l'option 1, ainsi que de ceux que Mike O a soulignés dans sa réponse.
En passant, je suis également en désaccord avec votre choix d’expression «défauts de sécurité». Je n'appellerais même pas les mots de passe en texte brut stockés sur le serveur une «faille de sécurité». Bien que j'appelle cela une pratique extrêmement mauvaise.
@ttt Bien que le texte brut ne soit pas un problème lors de la mise à jour du mécanisme de mot de passe, car vous saurez quoi hacher pour le crypté.
@TTT C'est pourquoi je n'utilise pas "l'option 1"; J'utilise un compromis qui fonctionne comme l'option 1 dans la pratique mais qui n'a pas le même effet sur les utilisateurs.
@MichealJohnson - vrai, je suppose que vous pourriez appeler votre suggestion "option 1.5", mais elle a toujours les inconvénients de l'option 1 - donne l'impression qu'il y avait un problème de sécurité et / ou une brèche, fournit la fenêtre d'interception de jetons comme Mike O l'a décrit , et introduit même un nouveau problème: cela pourrait attirer l'attention des attaquants et maintenant ils ont quelque chose à essayer de pirater - car s'ils ont accès au serveur, ils ont les hachages de mots de passe les plus faibles à exploiter. (Ce ne serait pas possible si vous faisiez réellement l'option 1.)
@TTT Comment les attaquants vont-ils savoir quels comptes ont des mots de passe plus faibles? De plus, du point de vue d'un attaquant du côté frontal du serveur, les mots de passe ne sont ni moins ni plus sécurisés car ils auraient encore besoin d'être forcés; c'est si l'attaquant s'empare des hachages que les mots de passe peuvent être compromis. Pour que cela fonctionne, l'attaquant doit avoir un compte enregistré sur le serveur, voler les hachages du serveur, puis savoir quels mots de passe utilisent quels hachages.
@MichealJohnson - Je suis d'accord avec vous. Rappelez-vous que le point de changer l'algorithme de hachage pour commencer est juste au cas où le serveur serait compromis. Une fois sur le serveur, il devrait y avoir quelque chose indiquant quel algorithme de hachage utiliser, afin que le code sache lequel essayer (et que l'attaquant puisse le voir aussi). Si vous n'avez pas d'indicateur, cela signifie que le code devrait essayer les deux algorithmes, mais le hachage de l'un serait un mot de passe valide pour l'autre. Voir le commentaire de kasperd à la question pour plus de détails à ce sujet.


Ce Q&R a été automatiquement traduit de la langue anglaise.Le contenu original est disponible sur stackexchange, que nous remercions pour la licence cc by-sa 3.0 sous laquelle il est distribué.
Loading...