BT

Diffuser les Connaissances et l'Innovation dans le Développement Logiciel d'Entreprise

Contribuez

Sujets

Sélectionner votre région

Accueil InfoQ Articles Comment stocker des mots de passe dans ma webapp (sans sel?)

Comment stocker des mots de passe dans ma webapp (sans sel?)

Favoris

Introduction

De nos jours, le mot de passe est au cœur de la vie numérique, et le vol d'identité se fait de plus en plus fréquent. Il est donc de notre devoir, en tant que développeurs d'applications (qu'elles soient web ou non), de tout faire pour nous assurer de la sécurité des informations de nos utilisateurs.

La multiplication des services que nous utilisons sur le web au quotidien est un challenge, car il nous faut retenir autant de mots de passe complexes, et l'utilisateur moyen doit être éduqué à la fois pour choisir un mot de passe suffisamment sécurisé, et suffisamment simple à garder en mémoire (car un mot de passe noté sur un post-it à côté de l'écran ne sert pas à grand chose). De même, il doit autant que faire se peut veiller à ne pas réutiliser le même mot de passe pour deux services qu'il considère critiques (par exemple l'email principal et la banque), car si l'un des deux services présente une brèche de sécurité, les pirates ne pourront ainsi pas accéder à son autre compte.

Mais ne serait-ce pas mieux de ne pas faciliter la tâche de tels pirates et de tout faire côté application pour ne pas que des informations critiques telles que les mots de passe ne soient accessibles ?

Dans cet article, je vais tenter de présenter l'évolution au cours du temps des différentes techniques de stockage de mot de passe, d'attaque sur ces informations (en cas de brèche de sécurité dans une application web) et de protection des mots de passe (afin de ne pas compromettre les comptes de nos utilisateurs dans d'autres applications une fois une brèche ouverte).

L'attaque directe ("Sésame ouvre toi !")

La force brute

L'une des premières possibilités que possède un pirate désireux d'accéder à votre compte (et donc l'une des premières qui se soient répandues par le passé) est la force brute ( brute force ), qui consiste tout simplement à faire essayer à un automate toutes les combinaisons possibles de caractères afin de "deviner" le mot de passe.

C'est bien évidemment une technique très "naïve" (il est très simple par exemple de limiter le nombre de tentatives d'accès à un site avant de renvoyer un utilisateur qui effectue trop d'essais ratés). On garde toutefois aujourd'hui encore trace de cette technique, puisque la plupart des sites web notent la sécurité d'un mot de passe en fonction de sa longueur et des combinaisons de chiffres, lettres, casse et symboles présents dans celui-ci (qui sont deux facteurs qui augmentent drastiquement le nombre d'essais nécessaires avant de trouver un mot de passe par force brute).

Il est donc relativement facile aujourd'hui d'éviter une telle attaque en direct, mais les utilisateurs n'abandonnent pas facilement leur habitude (une étude récente révèle par exemple que les mots de passe les plus utilisés comprennent "123456" et "password").

Les attaques par dictionnaires

Les pirates s'intéressant au comportement des utilisateurs ont pu se rendre compte que bien souvent ceux-ci, excédés d'avoir à retenir des mots de passe trop compliqués, décident d'utiliser des mots courants, peut-être en rajoutant une ou deux majuscules par ci par là. Naissent alors les attaques par dictionnaire, qui comme leur nom l'indique se basent sur des listes de mots communs et essayent ceux-ci en jouant sur les majuscules, plutôt que d'essayer lettre par lettre les mots de passe. Cela représente un nombre de tentatives moindre, et permet donc de trouver plus de mots de passe. On peut argumenter que, comme pour la force brute, limiter le nombre de tentatives de connexion semble régler le problème. Mais que se passe-t'il si un pirate arrive à accéder à notre serveur par la petite porte ? Comment alors limiter les dégâts ?

Limiter les dégâts : le cryptage des mots de passe

La sécurisation d'une application, ainsi que d'un serveur, est une affaire complexe. Si l'on prend en compte le fait que l'attaquant n'a qu'à trouver une seule faille dans le système pour s'y introduire, alors que le défenseur doit couvrir toutes ses bases, il n'est pas étonnant qu'une application faisant la cible d'un pirate déterminé finisse bien souvent par se faire infiltrer. Cloisonner les différentes parties de son système est une bonne idée, pour limiter les dégâts et multiplier les murailles de défense. Cependant on ne peut se contenter d'espérer que notre base de données, mots de passe compris, ne tombe jamais entre des mains malintentionnées. En effet, une fois la brèche ouverte il est trop tard pour notre application. En revanche, il ne faut pas que les choix de sécurité fait dessus impactent les autres applications de nos utilisateurs !

Le pire cas qu'il puisse arriver est de trouver les mots de passe des utilisateurs en clair dans la base. Associés à leurs logins respectifs, les pirates ont toute liberté d'usurper l'identité des utilisateurs. Pire, ils peuvent alors tester ces mêmes combinaisons sur d'autres services, car bien souvent les utilisateurs les réutilisent tels quels. Le site ou l'application la moins sécurisée deviens alors le maillon faible de la chaîne, et le hacking d'un site en apparence anodin peut se révéler impactant pour d'autres services plus critiques.

Pour répondre à l'apparition de ce genre d'attaques, les premières mesures mises en place ont été naturellement d'éviter cette situation en ne stockant pas le mot de passe en clair mais une version "cryptée" de celui-ci, passé par une fonction de hachage comme MD5 ou SHA1 (*note: ne les utilisez plus, elles sont dépassées*). Ces fonctions de hachage cryptographiques à sens unique permettent de facilement passer du mot de passe en clair à sa forme cryptée, mais pas l'inverse. De plus, connaître un couple mot de passe + hash n'apporte aucune indication sur les autres couples existants. Il existe des probabilités de collision (deux mots de passe différents produisant le même hash), mais celle-ci sont par conception les moins fréquentes possibles (et le sont d'autant moins normalement quand deux chaînes sources sont proches lexicalement).

Les tables de recherche et le salage

Une fois la mauvaise habitude de stocker des mots de passe en clair passée, et que l'utilisation des fonctions de hachage comme MD5 était devenu généralisée et facilitée (notamment par une présence directe de la fonction dans des langages comme PHP ou comme transformation à l'insertion dans des bases de données comme MySQL), les développeurs de webapps pensaient être tranquilles. Malheureusement, toutes ces techniques déjà en place depuis bien longtemps sur des systèmes comme Unix (crypt(3)) avaient par la même occasion fait l'objet de recherches et été éprouvées par le passé. Il existait donc déjà des techniques d'attaques sur ce genre de base de données.

Notamment, l'une des techniques consiste à préparer un dictionnaire d'attaque appelé table de recherche (*lookup table*) qui contient les hash de nombreux mots de passes/mots/chaînes de caractères. Il existe par exemple une table de recherche (en l’occurrence une variante permettant de stocker plus d'entrées appelée rainbow table) permettant de craquer n'importe quel mot de passe de 8 caractères ou moins stocké en MD5 ! Une autre variante est la table de recherche inversée, qui part d'une base de mots de passe compromise, regroupe les hash similaires et les associe à la liste des utilisateurs partageant ce hash (les utilisateurs pouvant souvent en fait avoir le même mot de passe) et permet à l'attaquant de se concentrer sur une attaque brute force ou par dictionnaire des hash qui l'intéresse.

La manière la plus sécurisée de stocker des hash face à des attaques de type tables de recherche est d'utiliser la technique du salage. Ce fameux sel (*salt*) est en fait une chaîne de caractères aléatoires, de préférence de la longueur finale du hash, qui est ajoutée au mot de passe en clair. De cette façon, le hash de password stocké dans notre base n'est pas le même que l'entrée correspondante dans la table de recherche de l'attaquant (à moins que celle-ci ai été générée avec le même sel). Attention toutefois, le salage ne protège pas contre les attaques en force brute, et il est de plus, facile de mal utiliser la technique.

Bien saler un mot de passe

La meilleure manière de procéder à un salage efficace de ses hash de mots de passe est de ne jamais réutiliser un sel. La plus grosse erreur que l'on pourrait faire est de ne générer qu'un seul sel aléatoire et le réutiliser pour le salage de tout les mots de passe. En effet, si l'attaquant obtient ce sel unique (et il est probable qu'il l'obtienne) il peut regénérer sa table de recherche avec le sel en question et la rendre à nouveau fonctionnelle.

Il faut donc générer un sel propre à chaque mot de passe (y compris quand l'utilisateur change son mot de passe), et suffisamment long pour que les tables de recherche n'aient pas été préparées en prenant en compte tout les sels possibles. On peut alors stocker le sel dans sa base à côté du hash (puisque même s'il a le sel d'une entrée, l'attaquant ne peut utiliser sa table et en est réduit à une attaque en force brute).

À l'ère des GPU

Avec l'arrivée sur le marché de cartes graphiques (GPU) de plus en plus puissantes, qui sont conçues pour effectuer des calculs de manière massivement parallèle, un nouveau type d'attaque est né aux environs de 2007. L'attaque la plus courante jusqu'alors était la table de recherche, mise en échec par l'usage correct de sels. Mais on l'a vu précédemment cette technique de défense n'offre quasiment pas de protection contre les attaque par force brute, et c'est cela que les GPU exploitent. En effet, la puissance de calcul d'un GPU est largement supérieure à celle d'un CPU en ce qui concerne des tentatives de craquage de mot de passe. En ayant à la fois le hash et son sel, on peut avec des outils spécialement conçus exploiter cette puissance de calcul en parallèle réussir à trouver le mot de passe original. La table de recherche est devenue obsolète!

L'une des caractéristiques inhérentes à la production des hash exergue de plus le problème. En effet, les différentes fonctions de hachage jusqu'alors utilisées sont des fonctions de hachage cryptographiques conçues pour être rapides. N'étant pas prévues à la base pour du stockage de mot de passe, et ayant des usages tels que le contrôle de cohérence sur de gros fichiers par exemple, elles se doivent de pouvoir être exécutées le plus rapidement possible sur un volume important de données. Et cela facilite en fait la tâche d'attaquants brutes puisqu'ils peuvent procéder très rapidement à de nombreux essais.

Les algorithmes de hachage cryptographiques à coût adaptable

Pour palier à ce problème, des algorithmes spécialisés ont depuis lors vu le jour. Ceux-ci sont orientés sécurisation des mots de passe et ont pour but à contrario des fonctions de hachage classiques de rendre l'opération de hachage la plus coûteuse possible dans la limite de ce que l'utilisateur pourra supporter. En effet, si la validation du mot de passe d'un utilisateur prend disons quelques secondes, celui-ci peut encore patienter. L'opération n'est de toutes façons pas fait très souvent, en comparaison du nombre de hachage qu'un pirate doit réaliser pour craquer par la force un mot de passe... L'attaquant est donc avec de telles fonctions très nettement désavantagé. L'état de l'art de ces fonctions de hachage cryptographique spécialisées sont dites "à coût adaptable", car elle peuvent être paramétrées pour augmenter le coût du hash.

bcrypt, présenté dès la fin des années 90 pour OpenBSD par Niels Provos et David Mazieres, permet de jouer sur le nombre d'itérations de hash et par la même occasion sur le coût en temps de l'opération. L'idée est d'augmenter ce paramètre au fur et à mesure que le matériel augmente en performance, pour garder un coût suffisamment haut pour prévenir des attaques.

scrypt, son successeur spirituel présenté en 2009 par Colin Percival et proposé comme standard IETF fin 2012, joue quand à lui en plus sur un coût en terme de mémoire. Comme nous sommes à l'ère de l'attaque par GPU, cela devient très intéressant car ce genre de matériel n'est justement pas adapté pour des calculs nécessitant beaucoup de mémoire locale, et la parallélisation massive d'une attaque n'est alors possible qu'avec de gros moyens financiers.

Ces deux fonctions gagneraient néanmoins à passer du giron des cryptanalystes à la connaissance d'un plus large public de développeurs. Les implémentations de scrypt dans les librairies et frameworks de sécurité par exemple sont encore rares.

Conclusion

La sécurisation d'une base de mots de passe est un point crucial à mettre en œuvre aujourd'hui, afin de cantonner d'éventuelles brèches de sécurité à nos applications et ainsi protéger le reste des données de nos utilisateurs. Mais les attaques se font de plus en plus complexes et efficaces, et il est donc facile de mal s'y prendre.

Dans cet article nous avons vu comment les techniques de hachage et de salage permettent de nous apporter une sécurité des mots de passe correcte face aux tables de recherche préparées à l'avance, et comment les dernières fonctions de hachage spécialisées limitent l'impact des puissants GPU contemporains dans la capacité des pirates à craquer nos mots de passe par la force brute massivement parallélisée.

Evaluer cet article

Pertinence
Style

Contenu Éducatif

BT