Je travaille sur l'amélioration d'un CMS où l'implémentation actuelle du stockage du mot de passe est simplement sha1(password)
. J'ai expliqué à mon patron que le faire de cette façon est incroyablement précaire et lui ai dit que nous devrions passer à bcrypt, et il a accepté.
Mon plan était de simplement exécuter tous les hachages existants via bcrypt et de les stocker dans le champ de mot de passe, puis d'utiliser le psudo-code suivant pour vérifier le mot de passe: correctPassword = bcrypt_verify(password, storedHash) or bcrypt_verify(sha1(password), storedHash)
.
De cette façon, les nouveaux utilisateurs ou les utilisateurs qui changent leurs mots de passe obtiendront de "vrais" hachages bcrypt, tandis que les utilisateurs existants n'auront pas tous à changer leurs mots de passe. Y a-t-il des inconvénients à faire cela? Alors qu'il serait probablement idéal de demander à tous les utilisateurs de choisir un nouveau mot de passe, perdons-nous beaucoup en termes de sécurité en faisant cela?
Je pensais que même si un attaquant avait accès à la fois à la base de données et au code, le craquage ne serait pas beaucoup plus rapide même si la majorité de l '"entrée" de bcrypt était une chaîne hexadécimale de 40 caractères, car la partie lente (bcrypt_verify()
) doit encore être invoquée pour chaque tentative de mot de passe sur chaque utilisateur.
En fait, c'est un bon moyen de protéger les mots de passe stockés de manière non sécurisée. Cependant, il y a un point faible dans ce schéma, qui peut être facilement surmonté en marquant les anciens hachages, donc je préférerais cette solution:
if (checkIfDoubleHash(storedHash))
correctPassword = bcrypt_verify(sha1(password), storedHash)
else
correctPassword = bcrypt_verify(password, storedHash)
Imaginez un attaquant qui récupère une ancienne sauvegarde. Il verrait les hachages SHA, et pourrait les utiliser directement comme mots de passe si vous testez avec bcrypt_verify(...) or bcrypt_verify(sha1(...))
.
La plupart des bibliothèques bcrypt ajoutent elles-mêmes une marque de l'algorithme utilisé, donc ce n'est pas un problème si vous ajoutez votre propre "double marque de hachage", mais bien sûr, vous pouvez également utiliser un champ de base de données distinct pour cela:
$2y$10$nOUIs5kJ7naTuTFkBy1veuK0kSxUFXfuaOKdOKf9xYT0KKIGSJwFa
|
hash-algorithm = 2y = BCrypt
Pourquoi ne pas simplement utiliser bcrypt (sha1 (mot de passe)) pour tous les mots de passe anciens et nouveaux? Cela évite le problème des personnes utilisant vos anciens hachages comme mots de passe et est également plus simple que votre proposition.
C'est une bonne stratégie, vous ne perdrez aucune sécurité à moins qu'un utilisateur ne décide de générer un mot de passe vraiment aléatoire de plus de 160 bits car il sera tronqué. La différence est donc minime. (auquel cas il faudrait encore beaucoup de temps pour forcer le texte original par bruteforce)
Vous pouvez choisir d'implémenter une logique pour migrer les mots de passe la prochaine fois qu'un utilisateur les modifie, mais je ne vois aucun risque qui nécessiterait un changement immédiat des mots de passe, sauf si vous pensez que les hachages ont fui.
J'ai récemment mis en place un système similaire pour la migration des mots de passe vers bcrypt. Cependant, au lieu de SHA1, nous utilisions à l'origine des hachages SHA256 (mot de passe + sel).
Ce sel est régénéré lorsque nous basculons l'utilisateur vers bcrypt lors de la connexion (facultatif) ou lors du changement de mot de passe. Le hachage ne serait donc pas basé sur l'original. Nous utilisons ensuite principalement ce nonce comme IV pour crypter le hachage bcrypt dans la base de données avec une clé stockée en dehors de la base de données.
Cela empêche uniquement les attaques par injection et les données extraites uniquement de la base de données fournissant des informations de mot de passe utiles. Mais les frais généraux ne nous préoccupaient pas et nous pouvons changer cette clé externe à tout moment.
L'utilisation du hachage SHA256 comme entrée pour bcrypt maintient également la longueur du mot de passe d'entrée en dessous du maximum pour bcrypt ( connexesarticles )
La seule préoccupation que j'ai vue également concernant l'utilisation de SHA1 de cette manière lorsque je cherchais des conseils et des problèmes avec tout ce que je faisais était de Thomas Pornin dans le deuxième de ces deux liens:
L'utilisation d'une fonction de hachage sécurisée pour prétraiter le mot de passe est sécurisée; il peut être démontré que si bcrypt (SHA-256 (mot de passe)) est cassé, alors soit le mot de passe a été deviné, soit une caractéristique de sécurité de SHA-256 s'est avérée fausse. Il n'est pas nécessaire de jouer avec le sel à ce niveau; hachez simplement le mot de passe, puis utilisez bcrypt sur le résultat (avec le sel, comme mandats bcrypt). SHA-256 est considéré comme une fonction de hachage sécurisée.
Il est donc possible que conserver SHA1 ne soit pas un bon choix - pourquoi sinon migrer de l'utiliser uniquement en premier lieu. Cela étant dit, il est improbable qu'il y ait une sorte d'attaque qui fournirait une valeur pratique pour attaquer un bcrypt (SHA1 (mot de passe)) dans un proche avenir qui n'impliquerait pas un compromis quelconque avec bcrypt lui-même.