Le stockage des mots de passe dans les systèmes UN*X

Publié le 12/06/2021.

Toute personne un temps soit peu versée dans la sécurité informatique le sait : il ne faut sous aucun prétexte stocker un mot de passe en clair. À la place, les applications (web ou non) stockent une empreinte numérique de ce mot de passe. Ainsi, lorsque vous vous connectez avec votre mot de passe, l'empreinte de ce dernier est calculée et, si elle correspond à l'empreinte enregistrée pour votre compte, la connexion s'effectue. Ces empreintes sont plus communément appelés des « hash ». Dans ce billet, nous nous intéresseront spécifiquement au stockage des mots de passe des comptes utilisateurs des systèmes de type UN*X.

Petite histoire des méthodes de hachage de mots de passe

Si l'on omet les premiers balbutiements, le stockage de mots de passes hachés apparaît dans les années 1970 sur le système UNIX, via la fonction crypt (à ne pas confondre avec l'utilitaire du même nom). À cette époque, cette fonction utilise l'algorithme de chiffrement symétrique DES développé par IBM. Le chiffrement étant alors considéré comme une arme et les loi américaines interdisant l'exportation de produits cryptographique, beaucoup de systèmes ne pouvaient pas se permettre de l'utiliser.

La démocratisation du hachage des mots de passe n'apparaît qu'à partir de 1995 quand, afin de palier à l'impossibilité d'utiliser une version fonctionnelle de crypt, Poul-Henning Kamp ajouta à cette fonction une nouvelle méthode de hachage basée sur l'algorithme MD5. Cette nouvelle fonction de hachage de mots de passe est généralement nommée md5crypt afin de la différencier de la véritable fonction MD5 que Poul-Henning Kamp n'a pas souhaité directement utiliser car, déjà à l'époque, il la trouvait trop rapide et il était donc réaliste de casser des hash de mots de passe par force brute. Du coup, afin de régler ce problème de rapidité, md5crypt effectue diverses manipulation sur l'empreinte. Ces manipulation n'ont aucune raison cryptographique autre que rallonger le temps d'exécution, l'auteur en décrivant certaines comme « vraiment bizarres ». Il s'agit vraiment plus d'une « danse de la pluie » que d'une opération cryptographique, bien qu'à l'époque c'était novateur et que l'on avait pas vraiment mieux.

Les années qui suivent voient se développer intensément les méthodes de hachage de mots de passe avec l'apparition en 1999 de Bcrypt puis, en 2000, de PBKDF2. Et c'est suite à l'arrivée de ces deux fonctions que la crise de succession commence.

Bcrypt ayant été créée par des développeurs d'OpenBSD pour ce système, elle est rapidement adoptée par ce dernier ainsi que par les autres système de cette famille. À cette fin, elle est ajoutée comme méthode de hachage supplémentaire dans crypt. Mais malgré une conception particulièrement robuste pour l'époque qui en font, encore à l'heure actuelle, un choix tout à fait acceptable, elle est basée sur Blowfish et non une fonction à sens unique approuvée par le NIST. En conséquent, les américains rechignent à l'utiliser.

Du côté de GNU/Linux la question se pose donc de savoir quelle fonction de hachage ajouter à crypt. Et malheureusement, malgré quelques rares distributions qui ont adoptées Bcrypt, ce point se règle principalement dans la glibc et sera donc tranché par le tristement célèbre Ulrich Drepper.

Pour vous faire une idée du personnage, Drepper est considéré comme un dictateur a l'égo surdimensionné. Il est réputé pour des choix techniques unilatéraux et régulièrement mauvais ainsi que pour être particulièrement désagréable. Bien entendu il refuse généralement d'expliquer ses choix, considérant sans doute que sa parole n'a pas a être remise en question.

Un tel profil ne pouvait conduire qu'à un désastre. C'est ainsi que, en 2007, il décida de faire avancer les choses et d'ajouter une nouvelle méthode de hachage à crypt. Bcrypt est écartée car ne répondant pas aux critères du NIST et PBKDF2, pourtant explicitement recommandée par le NIST, n'est même pas mentionnée dans sa réflexion sur le choix d'une nouvelle fonction. À la place, Drepper, n'ayant pourtant aucune qualification particulière en cryptographie, décrète que la « danse de la pluie » de md5crypt est une méthode sûre et il l'adapte pour deux fonctions de la famille SHA-2, SHA-256 et SHA-512, ce qui donne naissance à sha256crypt et sha512crypt. Notons que Poul-Henning Kamp lui-même indiqua en 2012 ce procédé ne comporte pas le moindre avantage.

Bien entendu, son égo gonflé par sa grotesque contribution, Drepper refusa toujours d'intégrer Bcrypt dans la glibc. Tout d'abord en 2006 où il laissera le ticket traîner le temps d'implémenter sa propre « solution », puis en 2011 où il indique simplement qu'il n'y a pas besoin d'autre chose de plus. Une troisième demande réalisée en 2014 reste dans les limbes.

Pour GNU/Linux, la solution passe par l'utilisation de la libxcrypt qui propose une version moderne de crypt en remplacement de la version de la glibc. Ainsi, le système de paquets d'ArchLinux supprime purement et simplement la version de crypt apportée par la glibc au profit de celle de libxcrypt. Cependant, bien que la libxcrypt ajoute des méthodes de hachage de mots de passe modernes à crypt, notamment yescrypt, ceci ne suffit généralement pas à faire en sorte que les mots de passes soient hachés par l'une de ces fonctions.

Il faut dire que, depuis cette période, les choses ont encore évoluées sur le sujet. De 2013 à 2015 s'est tenue la Password Hashing Competition durant laquelle un jury de spécialistes de la cryptographie a passé en revue toute une nouvelle génération de fonctions de hachage de mots de passe. De cette compétition est sortie une fonction gagnante, Argon2, ainsi que 4 autres fonctions s'étant particulièrement distinguées. Yescrypt est l'une de ces 4 fonctions.

La gestion des mots de passe dans les OS

Ça ne vous aura probablement pas échappé, mais crypt n'est qu'une fonction localisée dans une bibliothèque partagée. Elle ne fait rien par elle même, il faut que des programmes l'appellent. La gestion des mots de passe par le système d'exploitation n'y fait pas exception.

Shadow

Naturellement, l'authentification et le hachage des mots de passe se fait via les programmes de gestion des utilisateurs système, notamment useradd, usermod et passwd. Il existe plusieurs projets fournissant ces utilitaires ou des alternatives, mais nous nous concentrerons ici sur shadow qui est certainement la solution la plus populaire parmi les distributions GNU/Linux.

Devant s'adapter a de nombreuses configurations systèmes différente, shadow ne peut pas pré-supposer que crypt supporte les dernières méthodes de hachage disponibles. Afin de palier a ça, shadow permet de définir à la compilation les méthodes a supporter et, par défaut, ne supporte que les plus communes. C'est ainsi que par défaut --with-sha-crypt, apportant les méthodes d'Ulrich Drepper, est activé alors que --with-bcrypt est désactivé. Le paramètre --with-yescrypt est lui aussi désactivé par défaut et, du fait de son arrivée très récente, il n'est à l'heure actuelle présent que dans la version en développement de shadow.

La méthode traditionnelle de choix d'une méthode de hachage est donc de compiler shadow avec les méthode supportées par la version de crypt présente dans notre système puis d'utiliser le fichier /etc/login.defs afin d'y indiquer, dans la directive ENCRYPT_METHOD, la méthode de hachage que shadow doit utiliser lors de ses appels à crypt.

PAM

L'authentification étant un sujet complexe ne pouvant pas être réduit à des utilisateurs disposant de mots de passe, les systèmes UN*X modernes utilisent une solution modulaire bien plus pratique : PAM. Ainsi, PAM propose différents modules d'authentification et permet d'en créer de nouveaux. Un de ces modules, pam_unix, correspond à l'authentification d'un utilisateur système avec son mot de passe. Notons qu'il existe plusieurs implémentations différente de PAM, les systèmes GNU/Linux utilisant très majoritairement Linux-PAM.

Bien entendu, afin de tout fonctionne correctement, il est possible de compiler shadow avec le paramètre --with-libpam. Une fois compilé ainsi, shadow va, sauf cas particulier, ne plus lui-même utiliser crypt mais déléguer cette action à PAM.

Dès lors, c'est donc surtout la configuration du module pam_unix qui va décider de la manière dont sont hachés les mots de passe du système. Bonne nouvelle pour les utilisateurs de Linux-PAM : cette implémentation supporte libxcrypt et, en conséquent, son module pam_unix supporte yescrypt ainsi que d'autres méthodes de hachage. Cependant, la documentation de shadow indique qu'il est recommandé que la méthode de hachage définie dans /etc/login.defs corresponde à celle indiquée dans la configuration de PAM pour l'authentification système. Du coup, à moins de patcher votre version de shadow afin de lui apporter le support de yescrypt, vous devriez probablement attendre la prochaine version avant de configurer PAM de manière à utiliser yescrypt.

Pour information, la configuration de PAM se fait généralement dans le dossier /etc/pam.d/. Pour la configuration de l'authentification système, regardez les fichiers dont le nom commence par system-, en particulier /etc/pam.d/system-auth. De manière générale, chaque système d'exploitation intègre une configuration qui lui est propre. Sur ArchLinux, par exemple, cela se fait via le paquet pambase et le sujet fait débat..

Comment est stocké mon mot de passe ?

Afin de vérifier comment les mots de passe des utilisateurs de votre système sont stockés, le plus simple est de regarder directement les hash. Ces derniers se trouvent normalement dans le fichier /etc/shadow dont l'accès est réservé à root.

Ce fichier se présente sous un format texte où chaque ligne représente un utilisateur. Dans chaque ligne, un point-virgule sépare les différents éléments. Le premier élément est le nom de l'utilisateur, le second est le hash de son mot de passe et les éléments suivants ne nous intéressent pas.

À moins qu'il ne s'agisse de l'ancestrale méthode de hachage par DES ou un autre ancêtre, le hash du mot de passe se présente sous forme d'éléments séparés par le signe dollar, avec un dollar additionnel au début. Le premier des éléments nous renseigne sur la méthode de hachage utilisée :

  • 1 pour md5crypt
  • 2, 2a, 2x ou 2y pour Bcrypt
  • 5 pour sha256crypt
  • 6 pour sha512crypt
  • y pour yescrypt

Bien qu'il en existe d'autres, ces méthodes sont relativement rares et ne nous intéressent donc pas beaucoup. Vous trouverez généralement la liste des méthode supportée par votre implémentation de crypt dans les pages 3 ou 5 du manuel :

man 3 crypt
man 5 crypt

Quelle fonction de hachage choisir ?

Si les toutes premières ébauches basées sur DES ou MD5 sont de nos jours totalement obsolètes et n'offrent presque plus aucune protection, qu'en est-il des autres ?

N'en déplaise à l'omnipotent Ulrich Drepper, l'algorithme derrière sha256crypt et sha512crypt présente des faiblesses structurelles permettant d'accélérer sensiblement la rapidité de calcul. De plus, contrairement aux fonctions modernes, cet algorithme n'intègre aucune résistance basée sur l'occupation de l'espace mémoire. Ces deux méthodes de hachage sont donc a éviter.

À l'inverse, Bcrypt, bien que relativement ancienne, est toujours de nos jours considérée comme une fonction acceptable. Certes elle n'intègre pas les dernières avancées technologiques dans le domaine, mais elle reste tout de même fort correcte.

De la même époque, PBKDF2 n'a pas aussi bien vieillit bien qu'elle fasse toujours partie des fonctions recommandées par le NIST du moment qu'elle est utilisée avec une fonction de hachage approuvée.

Du côté des fonctions de nouvelles générations, sans surprise, Argon2, yescrypt et quelques autres telles que Balloon s'en sortent très bien. Ces fonctions, si elles sont bien configurées, apportent un haut niveau de sécurité aux mots de passe.

Malheureusement, en pratique toutes les fonctions ne sont pas implémentées dans crypt. Ainsi, la glibc ne propose rien de mieux que sha256crypt et sha512crypt. Les systèmes de la famille des BSD proposent en général Bcrypt, mais les accros du NIST ne peuvent pas l'utiliser. Comme évoqué plus haut, le salut vient certainement de libxcrypt qui implémente notamment yescrypt. Cette dernière fonction a l'avantage, contrairement à Argon2, d'être basée sur scrypt qui elle-même est basée sur PBKDF2-HMAC-SHA256. D'après la lecture que j'ai de la SP 800-63B, scrypt et yescrypt, bien que non-explicitement mentionnées, sont conformes à ces recommandations.

En résumé, passez à yescrypt dès que possible.