Dans l’épisode précédent "La sécurisation des mots de passe, c’est salée", j’avais expliqué l’intérêt du sel pour protéger les mots de passe de ses utilisateurs. On va voir désormais que cela n’est toujours pas suffisant, et que seul les poissons volants (blowfish) pourront nous sauver la mise !
Ajouté en 2017 : Bien que tout ce qui est expliqué ci-dessous dans cet article reste valable, depuis l’avénement de PHP 5.5, il est préférable d’utiliser la fonction password-hash pour hasher ses mots de passe en PHP. Cette fonction permet de gérer le sel, l’évolution de la complexité, et sera même capable d’utiliser d’autres algorithmes que bcrypt à l’avenir si le besoin s’en fait ressentir.
Bonne lecture !
Saler et hacher ne suffit pas
A la lecture de deux très bons articles sur le sujet : How to safely store a password (en), Exemple de stockage de mot de passe en Java : hashage et salage, est-ce suffisant ? ; on se rend compte que saler et hacher ne suffit pas !
Pour deux raisons :
- Nos super fonctions de hashage MD5, SHA-1, SHA-2… sont faites pour hasher beaucoup de données, 600 Mo pas de problèmes ! Pour l’authentification, on leur demande de hasher 6 à 20 charactères (une vingtaine d’octets) !
- Nos super fonctions de hashage MD5, SHA-1, SHA-2… sont bien trop rapides ! Et elles ont été conçue pour ça.
Si vous êtes capable de calculer très rapidement le hash d’un mot de passe, l’attaquant peut en faire autant ! Pire que tout, il va acheter le matériel qui va bien (ou le louer dans le cloud) pour être encore plus rapide ! Besoin de chiffres ? Regardez donc la puissance de quelques cartes graphiques : Speed estimations (ça date un peu… 2010. Je n’ai rien trouvé de plus récent.).
- Hasher 300 Mo en MD5 en 1 seconde ? Ce qui signifie qu’en 40 secondes on est capable de hasher tous les mots de passes de 6 caractères alphanumériques (en minuscule). 40 secondes ! Pour 100$ la GForce GTS240 vous fait ça sans efforts ! Les cartes graphiques les plus performantes (8 000$ quand même) vont jusqu’à 3 Go par secondes… Ah oui, quand même.
- SHA-1 pourra-t-il vous sauver ? Eh, mais pour 380$, je vous hashe 300 Mo en 1 seconde avec la GeForce GTX385 !
Moralité, on a beau mettre tout le sel qu’on veut, la vie pourra toujours devenir très fade d’un seul coup si un petit malin s’amuse avec votre base de données…
Appelons donc les poissons volants à la rescousses !
La vraie solution contre l’arc en ciel : les poissons volants
Il existe un algorithme appelé bfish ou bcrypt, basé sur Blowfish qui a la particularité d’être lent, je dirai même, aussi lent qu’on le souhaite. On peut configurer sa lenteur, et bien sûr les hash générés sont différents en fonction de ce paramétrage. ça se compte en milliseconde, mais c’est suffisant pour que la génération de dictionnaires de mots de passe hashés prennent des jours et des jours. On est donc bien protégé contre les attaques de type brute force ! En prime, il s’occupe du salage ce qui le rend donc très résistant aux rainbow tables.
Plus les puissances de calcul augmenteront, plus bcrypt s’effectuera rapidement. Avec le temps, il faudra donc augmenter le coefficient de ralentissement de notre implémentation (une petite variable à changer !). Jusqu’à ce que bcrypt ne suffisent plus… mais à ce moment là, on aura sûrement créé un autre algorithme 🙂 Par exemple scrypt qui a l’air bien prometteur, même si je n’ai pas trouvé d’implémentation de ce dernier pour l’instant.
Un petit exemple d’implémentation en PHP
L’algorithme bcrypt
n’est disponible en PHP que depuis la version 5.3. Mais jusqu’à PHP 5.4, il n’existe pas encore de méthodes vraiment simples pour utiliser bcrypt
, cela dit on peut se débrouiller avec la méthode crypt
.
En reprenant la même structure de code que précédemment on obtient alors :
// - Dans un fichier de configuration define('FonctionDeHachage', 'bcrypt'); // BCryptWorkFactor is the workload factor (12 -> around 300ms on a Core i7 machine), see http://php.net/crypt define('BCryptWorkFactor', 12); // - Fonction de hashage function bcrypt($password, $salt) { // 2a is the bcrypt algorithm selector, see http://php.net/crypt // Since PHP 5.4, it it recommanded to use 2y instead return crypt($password, '$2a$'.BCryptWorkFactor.'$' . $salt); } function password_hash($password, $salt) { // Bcrypt if (FonctionDeHachage == 'bcrypt') { $hash = bcrypt($password, $salt); } // Other algorithm else { $hash = hash(FonctionDeHachage, $password+$salt); } return $hash; } // Fonction de vérification function password_verify($givenPassword, $salt, $existingHash) { // Bcrypt if (FonctionDeHachage == 'bcrypt') { $hash = bcrypt($givenPassword, $salt); } // Other algorithm else { $hash = hash(FonctionDeHachage, $givenPassword+$salt); } return ($hash === $existingHash); }
Le tour est joué ! On peut désormais utiliser tout cela pour stocker le mot de passe lors de l’inscription d’un utilisateur.
// Data $username = 'Fylhan'; $newPassword = 'SuperPassw0rd'; $salt = time(); // Hash $passwordToBeStored = password_hash($newPassword , $salt); // Store data: $username, $salt, $passwordToBeStored
Et vérifier le password de l’utilisateur lorsqu’il s’authentifie :
// Data $username = 'Fylhan'; $goodPassword = 'SuperPassw0rd'; $badPassword = 'Beurk'; // Retrieve $salt for user 'Fylhan' // Verify goodPassword if (password_verify($goodPassword, $salt)) { echo 'Welcome home!'; } // Verify badPassword if (!password_verify($badPassword , $salt)) { echo 'Get lost!'; }
Pour un exemple en Java, je vous invite à consulter cet article Exemple de stockage de mot de passe en Java : hashage et salage, est-ce suffisant ? (fr).
Conclusion
Voilà, je crois que nous avons fait le tour :
- hashage,
- salage,
- réduction de la vitesse d’exécution avec
bcrypt
.
C’en est donc fini temporairement de cette partie "Sécurisation des mots de passe" ! Jusqu’à ce que scrypt
ou un autre algorithme fasse son apparition, ou sauf si j’ai encore loupé une étape… !
Par contre, la sécurité dans la gestion de l’authentification et des comptes utilisateurs regorgent encore d’autres sujets tous aussi intéressants et compliqués les uns que les autres 😉
Cet article est la troisième partie d’une série sur la sécurisation des mots de passe :
- Comment sécuriser les mots de passe de mes utilisateurs ? Le Hashage
- La sécurisation des mots de passe, c’est salée
- La sécurisation des mots de passe et les poissons volants
(Beaucoup) plus d’informations
- Souvenirs et poly du cours de sécurité du master 2 SEM du CNAM par Nicolas Pioch (2006, 2009)
- How to safely store a password (en)
- Salted Password Hashing – Doing it Right (en) Article très complet sur le sujet, expliquant notamment d’avantage comment on crack un hash
- Exemple de stockage de mot de passe en Java : hashage et salage, est-ce suffisant ?
- PHP The right way – Password hashing (en)
- Stack overflow – How do you use bcrypt for hasing passwords in PHP (bcrypt implementation)
- Bibliothèque PHPass (à regarder)
Ping : La sécurisation des mots de passe, c'est salée ! 30 minutes par jour