La sécurisation des mots de passe, c’est salée !

Publié dans Geekeries | Marqué avec ,
Share

Dans un précédent billet (Comment sécuriser les mots de passe de mes utilisateurs), j’expliquais quelques bases pour bien comprendre comment stocker convenablement le mot de passe de ses utilisateurs. Comme on l’a vu, il suffit d’enregistrer la valeur hachée du mot de passe (avec une bonne méthode de hashage comme SHA-1 ou SHA-2), pour éviter les conséquences désagréables sur la sécurité d’un vol de base de données !
Aujourd’hui, nous allons aller encore plus loin en tentant de contre-carré les attaques par dictionnaire ou pire par rainbow tables ! Pour cela, on aura besoin d’une bonne technique de salage (oui, avec du sel !), voire de poissons volants (blowfish >) !

Pourquoi un hashage simple est insuffisant

Mots de passe « faibles »

J’espère avoir le temps d’en reparler, mais afin de comprendre pourquoi un hashage simple de mots de passe est insuffisant, il faut avoir en tête qu’un pourcentage conséquent de vos utilisateurs choisiront des mots de passe faibles ! Par exemple : password1, abc123, myspace1, … comme le montre cette Etude sur les mots de passe les plus courants.
D’où l’importance d’une politique de fiabilité des mots de passe, mais c’est un autre sujet !

Eh, on parle d’une base de données de mots de passe ici !

Si l’utilisateur a accès à votre base de données (oui, c’est à sécuriser en premier lieu ;-)), cela veut dire qu’il peut faire ses petits calculs sur tous vos mots de passe, et donc les plus faibles vont tomber en premier ! Et puisque vous avez lu le paragaphe précédent, vous savez que certains mots de passe sont très faibles !
Par contre, si l’attaquant vise quelqu’un en particulier (vous par exemple), c’est bien plus difficile ! Connaissez-vous le paradoxe des anniversaires ?

Dictionnaire de mots de passe

Mais comment un attaquant ayant accès à votre base de données, va-t-il retrouver un mot de passe ? Il peut :

  • Tester toutes les combinaisons possibles. Bon courage 😉
  • Utiliser un dictionnaire des mots de passe les plus courants, pour tester si l’un de ces mots, haché, correspond à un des mots de passe de votre base de données. Se procurer, ou créer un de ces dictionnaires n’est pas très difficile.
  • Pire, utiliser une rainbow table, c’est-à-dire (en bref) un dictionnaire des mots de passe (automatiquement généré), mais déjà hachés avec SHA-1 ou SHA-2 ou autre ! Évidement, c’est la meilleure des solutions !

Bref, si l’attaquant a accès à votre base de données de mots de passe, il va très rapidement trouver un des mots de passe (sûrement le plus « faible »), et c’est déjà fichu ! Pire, sans autres mesures de protection, un attaquant pourrait même tenter un « brute force » sur votre formulaire d’authentification, et tenter ainsi de trouver votre mot de passe ! C’est moins facile à cause de la « lenteur » des requêtes HTTP, et du fait qu’il ne peut viser qu’un seul utilisateur à la fois, mais ça peut marcher…

Heureusement, le salage va nous aider à corriger (en partie) le premier problème, et à rendre plus difficile le second.

France Noirmoutier Sel brut

Première solution : le sel !

Le principe consiste à associer à chaque utilisateur une valeur aléatoire (par exemple : sa date d’inscription) que l’on sauvegarde. On appelle cette valeur aléatoire : le sel ! Quant au mot de passe, on lui ajoute ce sel, on hashe le tout, puis on sauvegarde !
Puisque ce sel est différent pour chaque utilisateur, l’attaquant doit maintenant créer une rainbow table spécifique pour chaque utilisateur, puisqu’il doit à chaque fois prendre son dictionnaire de mot de passe, y ajouter le sel d’un utilisateur, et le hasher. Et ça, c’est long ! Très long. Trop long !

Il n’est pas nécessaire de sécuriser le « sel » de chaque utilisateur. Certains insistent pour que la valeur utilisée soit suffisamment aléatoire, mais je ne vois franchement pas pourquoi puisque le résultat souhaité est atteins même une utilisant une simple data d’inscription. Bref, à méditer…
Mise à jour du 27 février 2013 : Après méditation (enfin surtout grâce au commentaire de JeromeJ), il semble bon en effet d’utiliser un sel assez aléatoire. Pour deux raisons :

  • si tout le monde utilise une date comme valeur pour le sel, eh bien il existe sûrement des algorithmes optimisés pour créer des dictionnaires avec des dates (on verra ça dans le prochain article, une histoire d’arc en ciel).
  • ça ne nous coûte pas grand chose 😉 (et ça coûte bien plus à l’attaquant !)

En résumé :

Stockage

  • Lors de l’inscription de l’utilisateur on créé le sel : sel = valeur aléatoire
  • On stocke dans la base de données : sel, hash(sel + mot de passe)
    • Exemple : sel = 8644jhg46j8, password = SuperPassw0rd.
    • On stocke : "8644jhg46j8", hash_sha2("8644jhg46j8"+"SuperPassw0rd").

Authentification

  • On récupère le sel de l’utilisateur à authentifier, et on l’ajoute au mot de passe qu’il nous a donné.
  • On hashe, et on compare tout ça avec le hash préalablement stocké dans la base.
  • Et on sait si le mot de passe est ok ou non !

Un petit exemple d’implémentation en PHP

Définissons d’abord nos fonctions pour hasher et vérifier. Vous remarquerez qu’il est possible de configurer l’algorithme de hashage à utiliser, et que je respecte l’interface de méthodes qui seront sûrement rajoutées dans PHP 5.5 (PHP The right way – password hashing). J’ai toutefois ajouté le « sel » en paramètre des fonctions pour des raisons pédagogiques 🙂

// Dans un fichier de configuration
define('FonctionDeHachage', 'sha512');
// Fonction de hashage
function password_hash($password, $salt) {
	$hash = hash(FonctionDeHachage, $password.$salt);
	return $hash;
}
// Fonction de vérification
function password_verify($givenPassword, $salt, $existingPasswordHash) {
	$hash = hash(FonctionDeHachage, $givenPassword.$salt);
	return ($hash === $existingPasswordHash);
}

Maintenant, utilisons tout cela pour stocker le mot de passe lors de l’inscription d’un utilisateur :

// Data
$username = 'Fylhan';
$newPassword = 'SuperPassw0rd';
$salt = mt_rand(1, 1000);
// 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!';
}

Conclusion

Voilà, vous pouvez respirer, vos mots de passe sont correctement sécurisés ! Enfin presque. Ou plutôt : pas du tout ! J’ai déliré avec les « poissons volants » dans mon introduction, et ce n’était pas pour du beurre salé (veuillez excuser ce jeu de mot bien fade) ! Rendez-vous au prochaine épisode pour en savoir plus…

Cet article est la deuxième partie d’une série sur la sécurisation des mots de passe :

(Beaucoup) plus d’informations

8 réponses à La sécurisation des mots de passe, c’est salée !

  1. Ping : Sécuriser les password des utilisateurs Hashage - 30 minutes par jour

  2. Ping : La sécurisation des mots de passe et les poissons volants 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>

*