Chapitre 3.8
Hash
Pourquoi les sites ne te redonnent jamais directement ton mot de passe si tu l'as oublié ?
La réponse est simple : ils ne le connaissent pas.
Pour prévenir une éventuelle fuite, un système sécurisé ne stocke jamais directement un mot de passe.
Les bases de données contiennent à la place un "hash".
Hashage
C'est un procédé qui applique un algorithme sur une donnée pour la transformer en une empreinte.
Par exemple, avec la phrase "explication hash" en entrée, l'algorithme "MD5" produit en sortie
"2ed235682e86c78381653b8247b41834".
Il existe de nombreux algorithmes, avec chacun ses propres techniques pour produire un hash sécurisé. La plupart partagent
les mêmes concepts de base :
- Il est impossible de recalculer l'entrée à partir du hash.
- Un hash a toujours la même longueur, peu importe l'entrée. C'est utile pour le stockage, et ça ne donne aucun indice à un éventuel attaquant.
- La même entrée provoque toujours la même sortie. Indispensable pour pouvoir comparer des hash, c'est comme ça qu'un site vérifie que le mot de passe saisi est le bon.
- La moindre modification dans l'entrée provoque un hash complètement différent. Par exemple, le MD5 de "explications hash" est "f17c7b19a8dcfa29fa75636e63cec1f4".
- Le risque de collisions doit être suffisamment faible pour qu'on considère le hash comme unique. C'est-à-dire que deux entrées différentes ne doivent pas provoquer la même sortie.
Sécurité
Un pirate qui vole une base de données se retrouve donc non pas avec une liste de mots de passe, mais avec une liste
de hash.
Il ne peut pas en calculer directement les mots de passe, mais il peut lancer dessus ce qu'on appelle une
"attaque au dictionnaire". Avant le vol, le pirate aura fait tourner un script qui remplit une base de données avec
le plus grand nombre possible de hash. Ce script calcule une par une toutes les possibilités : quel est le hash de "aaa", puis ensuite
celui de "aab", puis "aac"...
Le pirate n'a ensuite plus qu'à vérifier si certains hash volés correspondent à ceux qu'il a pré-calculés.
Bien sûr, le dictionnaire inclut déjà "password12345", "azerty" et n'importe quel mot de la langue courante.
C'est la raison pour laquelle les sites demandent des mots de passe toujours plus longs, avec des caractères
spéciaux.
Rainbow table
Les pirates sont sans cesse dans l'optimisation de leurs dictionnaires. Ils développent des techniques pour réduire les temps de calcul et surtout l'espace de stockage nécessaire. Les "rainbow tables" par exemple, sont des dictionnaires avancés qui permettent de recalculer des valeurs sans avoir besoin de stocker toutes les possibilités :
- Le pirate veut remplir sa base avec le mot "guide".
- Une fonction de hashage, un algorithme grand public comme MD5, transforme "guide" en "a0c391dc49c440fc9962168353cedde3".
- Ce hash est envoyé dans une "fonction de réduction". C'est un algorithme développé par le pirate, qui prend ce hash long et complexe et le réduit à quelque chose qui pourrait ressembler à un mot de passe. "a0c391dc49c440fc9962168353cedde3" devient "foo".
-
"foo" est hashé par MD5, ce qui donne "acbd18db4cc2f85cedef654fccc4a4d8", le résultat est réduit... Et ainsi de
suite 10 000 fois. À la fin, la dernière exécution
de la fonction de réduction donne "bar".
Dans sa base de données, le pirate va simplement stocker le couple "guide" et "bar". Il ne stocke jamais "foo" et les 10 000 autres valeurs intermédiaires. -
Le pirate vole les données d'un site et obtient le hash "acbd18db4cc2f85cedef654fccc4a4d8".
Il réduit ce hash et lance la boucle. À chaque tour de boucle, il vérifie s'il connaît le résultat.
À un moment, il tombe sur "bar". Il en déduit que le mot de passe qu'il cherche est quelque part dans la chaîne
entre "guide" et "bar". Il relance la boucle sur "guide" jusqu'à ce qu'il retombe sur l'étape md5("foo") =
"acbd18db4cc2f85cedef654fccc4a4d8".
Sans avoir stocké ce hash, le pirate retrouve que "foo" est probablement le mot de passe volé.
En contrepartie d'un gros besoin en puissance de calcul, une rainbow table réduit fortement la volumétrie stockée. Son efficacité dépend de la qualité de la fonction de réduction, du nombre d'itérations...
Le sel
Pour se protéger des dictionnaires, certains sites accentuent la sécurité de leurs mots de passe en ajoutant
du "sel". Le sel est une suite de caractères concaténée à l'entrée pour la rendre plus complexe.
Exemple : l'utilisateur choisit le mot de passe "GuideTech123?", le site va stocker un hash pour "99c_d!GuideTech123?3!N?ee7uIPlJ,S".
Historiquement, les développeurs ajoutaient du sel manuellement à la donnée avant de la fournir en entrée d'un
algorithme de hashage. Dans la grande majorité des cas, le sel était statique et commun à tous les utilisateurs.
Un pirate qui volait ce sel commun en même temps que la base de données pouvait rapidement se recréer une rainbow table.
Pour augmenter la sécurité, on a alors cherché à dynamiser le sel. Ça oblige le pirate à créer des dictionnaires
pour chaque valeur de sel possible. C'est beaucoup plus coûteux pour lui.
Beaucoup de développeurs ont utilisé pour ça des données du compte utilisateur, par exemple la date d'inscription. Ça fonctionne bien, mais ça implique que :
- Il faut avoir à disposition cette date d'inscription à chaque initialisation et vérification de mot de passe.
-
Pour vérifier le mot de passe, il faut d'abord récupérer le compte utilisateur à partir de l'identifiant (souvent un email), puis calculer le hash.
À l'inverse, d'habitude, nous calculons d'abord le hash, puis nous cherchons un compte qui correspond au couple identifiant et mot de passe.
Rechercher un compte client en premier rend le temps de traitement variable selon que le compte existe ou non. Ça ouvre une porte à une "attaque par mesure de temps". Le pirate peut déduire l'existence d'un identifiant valide et tenter de forcer le formulaire ou de communiquer avec sa victime.
Pour éviter ça, à une époque, certains ont tenté d'utiliser directement l'identifiant comme sel pour le mot de passe.
Mauvaise idée !
Un pirate qui a compris cette logique, et qui a déjà une liste d'identifiants, peut prendre son temps pour préparer des rainbow tables avant
le vol des hash.
Le temps est un élément crucial en cas de fuite de données. Aussitôt le hack détecté, il faut invalider les mots de passe
et inviter tous les utilisateurs à en changer sur tous les services pour lesquels ils utilisent le même.
Pour gagner du temps, il faut bloquer la possibilité au pirate de préparer ses dictionnaires en amont du vol.
La seule façon de limiter la préparation d'une attaque, c'est de générer les hash avec du sel aléatoire.
On a par contre besoin de stocker ce sel quelque part pour pouvoir ensuite vérifier les mots de passe lors de la connexion des clients.
Pour garder l'indépendance du hash et éviter de stocker le sel dans une source de données extérieure,
certains algorithmes modernes ont fait le choix d'intégrer le sel directement dans le hash et ainsi de le rendre public.
Exemple avec l'algorithme "bcrypt" : l'utilisateur choisit le mot de passe "vulgarisation". Pour le calcul du hash,
nous fournissons différents éléments de configuration à l'algorithme, notamment un sel aléatoire "J8qH4f3M7zD8XeA9nLhCjO".
Le résultat est "$2y$10$J8qH4f3M7zD8XeA9nLhCjODkOJW9pmrL2xI9T3Qt8wDWVmkVY5bxu".
Le sel est visible dans le hash, donc le pirate peut quand même lancer une attaque après le vol.
Mais comme le sel est aléatoire, il ne peut rien préparer à l'avance : il doit tout recommencer, utilisateur par utilisateur.
Autres utilisations
Les hash ne sont pas utilisés que pour les mots de passe :
- Ils peuvent être utilisés pour calculer ce qu'on appelle un "checksum", ou "somme de contrôle" en français. C'est une valeur calculée à partir d'un contenu, utilisée pour détecter des erreurs de transmission ou de stockage. Par exemple, si je télécharge un fichier important, l'émetteur du fichier peut mettre à disposition sa somme de contrôle et la manière de la calculer. Une fois le téléchargement terminé, je peux relancer le calcul de mon côté : si j'obtiens le même résultat, je suis sûr que le fichier n'est pas corrompu par une erreur réseau ou un pirate.
- Ils sont au coeur de certaines cryptomonnaies. Le principe de la preuve de travail, sur lequel se base le minage de Bitcoin, consiste à calculer aléatoirement des hash.
- Signature numérique de document, dédoublonnage de communications, identification de ressources... On en croise dès qu'on souhaite prendre l'empreinte d'un contenu.
Les algorithmes de hashage
Les algorithmes de hashage les plus connus et répandus sont MD5 et SHA-1.
Ils sont tous les deux considérés comme obsolètes... Depuis 2004 pour MD5 et 2017 pour SHA-1.
Les chercheurs arrivent en quelques minutes à provoquer des collisions volontaires pour ces deux algorithmes.
Ils peuvent faire passer un contenu pour un autre, notamment des fichiers infectés, sans que l'utilisateur ne puisse
s'en apercevoir car le checksum
résultant est identique.
Les systèmes modernes utilisent maintenant des alternatives plus sérieuses comme : SHA-256, bcrypt, argon...
Les anciens systèmes doivent trouver des moyens de migrer progressivement leurs hash MD5 vers des
solutions plus robustes :
obliger l'utilisateur à changer son mot de passe, remplir le nouveau hash lors de la reconnexion, etc.
