Le stockage des mots de passe est l'un des points de sécurité les plus importants si vous souhaitez protéger vos utilisateurs. Il est fréquent que ceux-ci utilisent le même mot de passe sur plusieurs sites, même si cette pratique est fortement déconseillée. De plus, il n’existe aucun moyen de lutter contre ce phénomène. On peut facilement imaginer ce qui peut se passer si une personne venait à extraire de votre base de données la liste des mots de passe de vos utilisateurs. Le hacker en question serait alors capable de se connecter aux comptes de vos utilisateurs, mais probablement à leurs autres comptes sur Internet. Il est par conséquent indispensable de stocker les mots de passe utilisateurs de manière sûre.
Mais pourtant ma base de données est sécurisée et il n’est pas possible d’accéder à son contenu si on n'est pas autorisé !
Oui, votre base de données est sûre, du moins je l’espère. Cependant on n’est jamais à l’abri d’une faille de sécurité dans une application. Les sites LinkedIn et LastFM en on fait les frais l’année dernière (2012). Plusieurs millions de mots de passe ont ainsi été dérobés, obligeant ces entreprises à demander à leurs clients de le modifier : une situation particulièrement inconfortable.
Garder les mots de passe en clair
Il s’agit clairement de la la solution à ne surtout pas utiliser. Si un intrus arrive à accéder à votre BDD, il aura directement accès aux mots de passe de vos utilisateurs. Il s’agit clairement de la pire solution que vous pouvez mettre en place. Elle est à bannir immédiatement.
Et bien, il me suffit d’utiliser une fonction de hachage comme MD5 ou SHA1...
Utilisation d’un hash
Les spécialistes en cryptographie ont mis au point des fonctions de hachage ou " fonction à sens unique ". Elles sont très pratiques et simples à calculer. L’idée est simplement d’utiliser une fonction de hachage comme MD5 ou SHA1 afin de calculer une empreinte du mot de passe. Ensuite, cette empreinte est stockée en base et utilisée pour tester le mot de passe. Elle est extrêmement simple à calculer à partir du mot de passe, mais étant donné que la fonction utilisée est à sens unique, il est difficile de retrouver le mot de passe.
Super, si quelqu’un accède au contenu de ma base de données il n’aura pas accès aux mots de passe..
Oui, mais il existe un problème... Pour commencer, les utilisateurs utilisent souvent des mots de passe relativement simples. Si votre assaillant est assez malin, il va alors essayer des mots du dictionnaire associés avec quelques chiffres (je vous rappelle que calculer un hash est simple). Et voilà ! Si votre mot de passe était " bonjour74 ″, le hacker peut alors le deviner en quelque secondes seulement. Il peut également connaître tous les utilisateurs ayant le même mot de passe, l’empreinte étant la même pour tous ces protagonistes. Pire encore : vous pouvez trouver sur Internet des tables pré-calculées (tables arc-en-ciel) permettant de retrouver très facilement un mot de passe d’une longueur allant jusqu’à une dizaine de caractères à partir de son empreinte.
Saler vos mots de passe
Une solution pour lutter contre les tables arc-en-ciel est d’ajouter un sel au mot de passe, c'est-à-dire une chaîne de caractères aléatoires. Cette dernière doit être unique pour tous les utilisateurs et stockée en clair dans la base de données. De cette manière, il reste simple de calculer l’empreinte du mot de passe et il est impossible d’utiliser des données pré-calculées. Un autre avantage de cette méthode : elle empêche de retrouver les utilisateurs utilisant le même mot de passe.
Cependant, il existe encore un problème. Je vous ai expliqué que calculer l’empreinte est rapide. En réalité, c’est très même rapide : un ordinateur récent est capable de calculer plus d’un milliard de hashs (MD5 ou SHA-1) par seconde. Il devient donc possible de simplement faire un brut-force sur la liste de mots de passe afin de les deviner.
Recommandation 2019 (HMAC + BCrypt)
Vous l’avez sûrement compris, les fonctions de hachage couramment utilisées telles que MD5 et SHA1 un défaut important. Elles sont beaucoup trop rapides à calculer et par conséquent peu adaptées pour le stockage des mots de passe. La solution que j’ai donc retenue est celle proposée par Mozilla dans ses recommandations sur la sécurité des services web. Elles proposent de se baser sur un système utilisant BCrypt et HMAC.
hashedPassword = bcrypt(HMAC(password, local_salt),bcrypt_salt)
Le hachage du mot de passe se passe alors en 2 étapes. Dans un premier temps, on calcule une empreinte HMAC intermédiaire en utilisant une clé secrète stockée dans un fichier local. Cette empreinte est ensuite hachée en utilisant BCrypt.
Cette méthode présente plusieurs intérêts :
- BCrypt est un algorithme de hachage volontairement lent, utiliser une technique de brut-force prendrait beaucoup trop de temps. De plus, la complexité de cette opération est adaptable. Il est donc possible de la ralentir en fonction de l’évolution des performances des machines.
- Les données utilisées avec BCrypt sont sécurisées par une clé stockée en local. Il est donc nécessaire de réussir à accéder au contenu de la base de données, mais aussi au système de fichiers pour obtenir la clé utilisée par HMAC. Sans quoi, les données obtenues seraient inutilisables.
- HMAC et BCrypt sont des fonctions de cryptographie sûres pour lesquelles il n’existe pas encore d’attaque connue.
Mozilla fournit une implémentation pour Python de ce mécanisme de stockage. Vous pouvez le trouver sur GitHub à l’adresse suivante : https://github.com/fwenzel/django-sha2.
Si vous utilisez du Java, vous pouvez trouver mon implémentation sur Gist.