web-dev-qa-db-fra.com

Pourquoi les hachages salés sont-ils plus sûrs pour le stockage des mots de passe?

Je sais qu'il y a beaucoup de discussions sur les hachages salés, et je comprends que le but est de rendre impossible la construction d'une table Rainbow de tous les hachages possibles (généralement jusqu'à 7 caractères).

Ma compréhension est que les valeurs salées aléatoires sont simplement concaténées au hachage du mot de passe. Pourquoi une table Rainbow ne peut-elle pas être utilisée contre le hachage de mot de passe et ignorer les X premiers bits connus pour être le hachage de sel aléatoire?

Mise à jour

Merci pour les réponses. Je suppose que cela fonctionne, l'annuaire (LDAP, etc.) doit stocker un sel spécifique à chaque utilisateur, ou il semble que le sel soit "perdu" et que l'authentification ne puisse jamais avoir lieu.

250
Tsyras

Cela fonctionne généralement comme ceci:

Dites que votre mot de passe est "baseball". Je pourrais simplement le stocker brut, mais toute personne qui obtient ma base de données obtient le mot de passe. Donc à la place, je fais un hachage SHA1 dessus, et j'obtiens ceci:

$ echo -n baseball | sha1sum
a2c901c8c6dea98958c219f6f2d038c44dc5d362

Théoriquement, il est impossible d'inverser un hachage SHA1. Mais allez faire ne recherche google sur cette chaîne exacte , et vous n'aurez aucun problème à récupérer le mot de passe d'origine.

De plus, si deux utilisateurs de la base de données ont le même mot de passe, ils auront le même hachage SHA1. Et si l'un d'eux a un indice de mot de passe qui dit try "baseball" - bien maintenant je sais ce que les deux sont les mots de passe des utilisateurs.

Donc, avant de le hacher, nous ajoutons une chaîne unique. Pas un secret, juste quelque chose d'unique. Que diriez-vous WquZ012C. Alors maintenant, nous hachons la chaîne WquZ012Cbaseball. Cela correspond à ceci:

c5e635ec235a51e89f6ed7d4857afe58663d54f5

Googler cette chaîne ne donne rien (sauf peut-être ceci page), alors maintenant nous sommes sur quelque chose. Et si person2 utilise également "baseball" comme mot de passe, nous utilisons un sel différent et obtenons un hachage différent.

Bien sûr, pour tester votre mot de passe, vous devez savoir ce qu'est le sel. Nous devons donc stocker cela quelque part. La plupart des implémentations le collent juste là avec le hachage, généralement avec un délimiteur. Essayez ceci si vous avez openssl installé:

[tylerl ~]$ openssl passwd -1
Password: baseball
Verifying - Password: baseball
$1$oaagVya9$NMvf1IyubxEYvrZTRSLgk0

Cela nous donne un hachage en utilisant la bibliothèque standard crypt. Notre hachage est donc $1$oaagVya9$NMvf1IyubxEYvrZTRSLgk0: il s'agit en fait de 3 sections séparées par $. Je vais remplacer le délimiteur par un espace pour le rendre plus clair visuellement:

$1$oaagVya9$NMvf1IyubxEYvrZTRSLgk0
 1 oaagVya9 NMvf1IyubxEYvrZTRSLgk0

Si je relance le processus, j'obtiens un hachage complètement différent avec un sel différent. Dans cet exemple, il y a environ 1014 façons de stocker ce mot de passe. Tous ces éléments concernent le mot de passe "baseball":

$1$9XsNo9.P$kTPuyvrHqsJJuCci3zLwL.
$1$nLEOCtx6$uSnz6PF8q3YuUhB3rLTC3/
$1$/jZJXTF3$OqDuk8T/cEIGpeKWfsamf.
$1$2lC.Cb/U$KR0jkhpeb1sz.UIqvfYOR.

Mais, si je spécifie délibérément le sel que je veux vérifier, je récupérerai mon résultat attendu:

[tylerl ~]$ openssl passwd -1 -salt oaagVya9
Password: baseball
Verifying - Password: baseball
$1$oaagVya9$NMvf1IyubxEYvrZTRSLgk0

Et c'est le test que je lance pour vérifier si le mot de passe est correct. Trouvez le hachage stocké pour l'utilisateur, recherchez le sel enregistré, réexécutez ce même hachage en utilisant du sel enregistré, vérifiez si le résultat correspond au hachage d'origine.

Mettre en œuvre vous-même

Pour être clair, ce message n'est pas un guide de mise en œuvre. Ne salez pas simplement votre MD5 et qualifiez-le de bon. Ce n'est pas suffisant dans le climat de risque actuel. Vous voudrez plutôt exécuter un processus itératif qui exécute la fonction de hachage des milliers de fois. Cela a été expliqué ailleurs plusieurs fois, donc je ne reviendrai pas sur le "pourquoi" ici.

Il existe plusieurs options bien établies et fiables pour ce faire:

  • crypt: La fonction que j'ai utilisée ci-dessus est une ancienne variante du mécanisme de hachage de mot de passe unix crypt construit- dans tous les systèmes d'exploitation Unix/Linux. La version originale (basée sur DES) est horriblement précaire; n'y pensez même pas. Celui que j'ai montré (basé sur MD5) est meilleur, mais ne devrait toujours pas être utilisé aujourd'hui. Les variations ultérieures, y compris les variations SHA-256 et SHA-512 devraient être raisonnables. Toutes les variantes récentes implémentent plusieurs séries de hachages.

  • bcrypt: La version Blowfish de l'appel fonctionnel crypt mentionné ci-dessus. Capitalise sur le fait que Blowfish a un processus de configuration de clé très coûteux et prend un paramètre de "coût" qui augmente le temps de configuration de clé en conséquence.

  • PBKDF2: ("Fonction de dérivation de clé basée sur mot de passe version 2") Créé pour produire des clés cryptographiques solides à partir de mots de passe simples, ce est la seule fonction répertoriée ici qui a en fait un RFC . Exécute un nombre configurable de tours, à chaque tour il hache le mot de passe plus le résultat du tour précédent. Le premier tour utilise un sel. Il convient de noter que son objectif initial était créer des clés solides, pas stocker des mots de passe, mais le chevauchement des objectifs en fait également une solution de confiance. . Si vous n'aviez aucune bibliothèque disponible et que vous étiez obligé d'implémenter quelque chose à partir de zéro, c'est l'option la plus simple et la mieux documentée. Bien sûr, il est toujours préférable d'utiliser une bibliothèque bien vérifiée.

  • scrypt: Un système récemment introduit spécialement conçu pour être difficile à implémenter sur du matériel dédié. En plus d'exiger plusieurs tours d'une fonction de hachage, scrypt a également un très grand état de mémoire de travail, de manière à augmenter l'exigence RAM pour les implémentations. très nouveau et pour la plupart non éprouvé, il semble au moins aussi sûr que les autres, et peut-être le plus sûr de tous.

402
tylerl

Techniquement, vous pouvez toujours utiliser une table Rainbow pour attaquer les hachages salés. Mais seulement techniquement. Un hachage salé vainc les attaques de la table Rainbow, non pas en ajoutant de la magie cryptographique, mais simplement en augmentant de façon exponentielle la taille de la table Rainbow nécessaire pour trouver avec succès une collision.

Et oui, vous devrez stocker le sel :)

49
xkcd

Il n'est pas ajouté après le hachage. Il est ajouté avant le hachage, donc le hachage est complètement différent pour chaque sel.

Ce n'est pas

hash abcd = defg
store 123defg (for user with 123 salt) and 456defg (for user with 456 salt)  

C'est

hash 123abcd = ghij 
hash 456abcd = klmn
23
AJ Henderson

Pour les hachages de mot de passe, vous devez utiliser quelque chose comme PBKDF2/RFC2898/PKCS5v2 , Bcrypt ou Scrypt, qui vous permettent tous de sélectionner une quantité d'itérations ("facteur de travail"), plutôt qu'une seule . PBKDF2, par exemple, utilise HMAC hachage à clé avec un algorithme de hachage bien connu (généralement SHA-512, SHA-256 ou SHA-1) en interne pour un nombre d'itérations, de préférence des dizaines à des centaines de milliers aussi élevé que vous pouvez le garder sans que les utilisateurs se plaignent, essentiellement.

La raison du grand nombre d'itérations est de ralentir un attaquant, ce qui à son tour réduit l'espace de clés qu'ils peuvent traverser dans une période de temps donnée, de sorte qu'ils ne peuvent pas attaquer efficacement les meilleurs mots de passe. "mot de passe" et "P @ $$ w0rd" vont être crackés malgré une attaque hors ligne, évidemment.

Vous avez raison, chaque ligne (utilisateur) a besoin de son propre sel long généré de manière unique et cryptographiquement aléatoire. Ce sel est stocké sous forme de texte en clair.

Avec PBKDF2, Bcrypt ou Scrypt, je recommanderais également de stocker le nombre d'itérations (facteur de travail) dans la base de données également, donc il est facile de changer (personnellement, j'utilise un nombre d'itérations quelque peu aléatoire - si c'est toujours différent , alors il y a moins de crainte à propos de "oh non, un petit changement pourrait tout gâcher - NE JAMAIS CHANGER ENCORE" de la direction ou d'autres développeurs

Notez que lorsque vous utilisez PBKDF2 pour le hachage de mot de passe, ne demandez jamais une sortie plus grande que la sortie de hachage native - pour SHA-1, c'est 20 octets, et pour SHA-512, c'est 64 octets.

Pour donner des exemples réels de PBKDF2 avec deux sels différents:

(PBKDF2 HMAC sel mot de passe itérations résultats octets de sortie)

  • PBKDF2 HMAC-SHA-512 MyPass vA8u3v4qzCdb 131072 64
    • 2e3259bece6992f012966cbf5803103fdea7957ac20f3ec305d62994a3f4f088f26cc3889053fb59a4e3c282f55e9179695609ee1147cffae1455880993ef874
  • PBKDF2 HMAC-SHA-512 MyPass l6eZQVf7J65S 131072 64
    • 1018ad648096f7814bc2786972eb4091f6c36761a8262183c24b0f4d34abb48073ed2541ee273220915638b46ec14dfb2b23ad64c4aa12f97158340bdc12fc57
15
Anti-weakpasswords

En plus de ce que Tylerl a dit, il est important de souligner que dans la cryptographie moderne, les sels ne sont pas utilisés pour se protéger contre les tables Rainbow. Personne n'utilise vraiment les tables Rainbow. Le vrai danger est la parallélisation:

  • Si vous n'avez pas de sel, ou seulement un sel statique , et que je vole votre base de données d'un million de hachages, je peux jeter tous mes cœurs à le renforcer brutalement, et chaque noyau attaquera un million de hachages simultanément, car chaque fois que je frappe n'importe quelle des chaînes utilisées comme mots de passe, je verrai une correspondance de hachage. J'ai donc besoin d'épuiser l'espace de recherche ne fois pour casser un million mots de passe. C'est une échelle complètement réaliste de fuite de mot de passe et une cible suffisamment attrayante pour lancer quelques dizaines de GPU ou même un FPGA personnalisé. Même si je n'épuise que les 30% inférieurs de l'espace de recherche, je continuerai à m'en aller avec 500 000 mots de passe réels. Ces mots de passe seront ensuite utilisés pour construire mon dictionnaire, donc la prochaine fois que quelqu'un fuit une base de données de hachage, je vais en casser 90% en quelques heures.
  • Si au lieu de cela, chaque mot de passe est haché avec son propre sel unique, alors je devrai attaquer chacun d'eux individuellement, car même les mots de passe identiques auront des hachages complètement différents stockés. Cela signifie que je pourrais peut-être utiliser ma ferme GPU/FPGA gourmande en énergie pour attaquer les deux cibles de grande valeur (par exemple, si Obama était votre utilisateur, obtenir son mot de passe justifierait tout de même les dépenses), mais je n'obtiendrai pas plusieurs centaines de milliers de mots de passe gratuitement. Si je voulais obtenir la totalité des mots de passe millions, je devrais effectuer une recherche par force brute complète --- millions fois.

Et c'est pourquoi tout sel, statique ou non, vous protégera contre les tables Rainbow préparées tant qu'il n'est pas largement utilisé, mais seuls les sels de hachage uniques vous protégeront contre le danger réel d'utiliser beaucoup de puissance de calcul parallèle pour tout casser immediatement.

14
mathrick

C'est plus sûr car lorsque plusieurs personnes ont le même mot de passe, elles auront un hachage différent.

Implémentation simple à l'aide de Python:

import hashlib

passwordA = '123456'
passwordB = '123456'

hashlib.md5(passwordA).hexdigest()
'e10adc3949ba59abbe56e057f20f883e'

hashlib.md5(passwordB).hexdigest()
'e10adc3949ba59abbe56e057f20f883e'

Et maintenant, ajoutons du sel:

saltA = 'qwerty'
salbB = 'asdfgh'

passA = passwordA + saltA
passB = passwordB + saltB

hashlib.md5(passA).hexdigest()
'086e1b7e1c12ba37cd473670b3a15214'

hashlib.md5(passB).hexdigest()
'dc14768ac9876b3795cbf52c846e6847'

Il s'agit d'une version très simplifiée. Vous pouvez ajouter du sel où vous le souhaitez. Au début/milieu/fin du mot de passe.

Le sel est très utile, surtout lorsque vous avez beaucoup d'utilisateurs, donc chacun aura des hachages différents. Imaginez maintenant la probabilité d'avoir les mêmes mots de passe pour des millions de comptes, tels que Facebook ou Google ou Twitter.

11
zakiakhmad

Premièrement, si deux utilisateurs utilisent le mot de passe plutôt faible "baseball", alors le craquage d'un mot de passe n'aide pas du tout à craquer le deuxième mot de passe à cause du salage. Sans salage, vous avez craqué deux mots de passe pour le prix d'un.

Deuxièmement, les tables Rainbow contiennent des hachages pré-calculés. Ainsi, un pirate pourrait rechercher le hachage de "baseball" dans une table Rainbow avec un gazillion d'entrées. Beaucoup plus rapide que le calcul des hachages de gazillions dans la table Rainbow. Et cela est empêché par le salage.

Et maintenant un point important: certaines personnes ont de bons mots de passe, d'autres ont de mauvais mots de passe. Si vous avez un million d'utilisateurs et que trois utilisent le même mot de passe, il vous suffit de savoir ce mot de passe est faible. Sans salage, vous disposez de trois hachages identiques. Donc, si quelqu'un vole votre base de données de hachages, il peut immédiatement voir quels utilisateurs ont des mots de passe faibles et se concentrer sur les casser. Il est beaucoup plus facile de casser le "baseball" que 1keOj29fa0romn. Sans salage, les mots de passe faibles ressortent. Avec le salage, le pirate n'a aucune idée des mots de passe qui sont faibles et ceux qui sont difficiles à déchiffrer.

8
gnasher729

Que le hachage soit salé ou non ne fait de différence que si l'attaquant a le hachage du mot de passe. Sans sel, le hachage peut être attaqué avec une table Rainbow: un dictionnaire pré-calculé qui associe les mots de passe aux hachages. Un sel de N bits augmente les besoins de stockage d'une table Rainbow et le temps de calcul de cette table, d'un facteur 2 ** N. Ainsi, par exemple, avec un sel 32 bits, une seule entrée de dictionnaire de table Rainbow, par exemple pour le mot de passe passw0rd, nécessite de nombreux gigaoctets de stockage, ce qui rend une telle table Rainbow très coûteuse en utilisant le matériel de stockage actuel. Ainsi, lorsqu'un sel est présent, l'attaquant est réduit à une attaque par force brute sur l'ensemble spécifique de hachages de mot de passe qui ont été obtenus.

Toutefois:

  • pour les mots de passe faibles, une attaque par force brute réussira en relativement peu de temps.
  • des mots de passe suffisamment forts ne seront pas trouvés dans une table Rainbow.
  • si l'attaquant a accès aux hachages, la sécurité du système est déjà compromise: les systèmes et protocoles modernes ne révèlent pas leurs hachages de mot de passe. Si l'attaquant n'est pas en mesure d'accéder à la base de données de mots de passe, les mots de passe peuvent également être stockés en texte brut.
  • si un attaquant doit compromettre le système pour accéder aux hachages afin d'en inverser les mots de passe, alors les seuls mots de passe qui ont de la valeur pour l'attaquant sont ceux qui sont réutilisés pour d'autres domaines de sécurité auxquels l'attaquant n'a pas encore accès. Les mots de passe qui ne sont pas réutilisés n'ont aucune valeur (et certainement moins de valeur que d'autres informations sensibles associées aux comptes).

Supposons que l'utilisateur joewestlake utilise le mot de passe god1234. L'attaquant inverse instantanément cela en utilisant une table Rainbow. (Ou quelques minutes à peine après avoir craqué à l'aide d'une attaque par force brute, si le hachage est salé, car le mot de passe est si mauvais.) Maintenant, le problème est que joewestlake a également utilisé god1234 pour son compte Gmail et pour les services bancaires en ligne, oups! Désormais, l'attaquant lit les courriels de Joe et en apprend suffisamment sur Joe pour qu'il puisse facilement répondre à la question "quel était le nom de votre premier animal de compagnie" lors de sa connexion aux services bancaires en ligne de Joe.

Ainsi, la justification des sels est qu'ils quelque peu protègent les utilisateurs en rendant les mots de passe de sécurité moyenne plus difficiles à inverser: les mots de passe qui, sans sel, pourraient raisonnablement être devrait se trouver dans une table Rainbow, mais qui sont suffisamment solides pour que le forçage brutal individuel prenne beaucoup de temps. Mais les sels n'offrent cet avantage que dans le cas où les hachages sont compromis, ce qui constitue déjà une grave violation de la sécurité, et l'avantage est uniquement pour les utilisateurs qui réutilisent leurs mots de passe de sécurité moyenne dans d'autres systèmes.

Dites que Joe a plutôt utilisé un mot de passe composé de 10 caractères alphanumériques aléatoires et symboles. Cela pourrait toujours être dans une table Rainbow, mais prend beaucoup de travail. Ainsi, même si Joe a utilisé le même mot de passe pour Gmail et les services bancaires en ligne, il est en sécurité, grâce au sel. Le pirate exécute sa fissure par force brute pendant peut-être plusieurs heures, voire plusieurs jours. La fissure donne de nombreux mots de passe faibles provenant d'autres utilisateurs du même système qui ont des mots de passe faibles. L'attaquant est satisfait de ce rendement et arrête de se fissurer; Le mot de passe de Joe n'est jamais inversé.

De plus, si la violation est détectée et que les utilisateurs (y compris Joe) sont invités à changer leurs mots de passe, alors Joe a une chance de dépasser les tentatives de piratage de l'attaquant, même si l'attaquant persiste à attaquer l'intégralité de l'espace de mot de passe de sécurité moyenne qui inclut le mot de passe de Joe . Joe le sait, le mot de passe qu'il a utilisé sur le système compromis est exactement le même que son mot de passe Gmail et bancaire, il s'efforce donc de changer les deux autres. Le sel aide ici car il permet aux utilisateurs de réutiliser un mot de passe de changer leur mot de passe. Le sel n'aidera pas ceux qui ont des mots de passe très faibles qui sont fissurés en quelques minutes, mais les utilisateurs de mots de passe qui mettent des heures ou des jours à se fissurer ont une chance de se battre.

1
Kaz