La sécurisation des mots de passe et les poissons volants

Publié dans Geekeries | Marqué avec ,
Share

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 !

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

BblowfishIl 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 :

(Beaucoup) plus d’informations

Une réponse à La sécurisation des mots de passe et les poissons volants

  1. Ping : La sécurisation des mots de passe, c'est salée ! 30 minutes par jour

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

*