J'espère que toutes les fuites de données de ces dernières années ont laissé une empreinte indélébile dans l'esprit des développeurs : Ne jamais stocker des mots de passe en clair dans une base de données. Jamais.

Une fois ce rappel obligatoire fait, nous pouvons passer au cœur du problème, à savoir : quelles sont les bonnes pratiques pour stocker les mots de passe de vos utilisateurs ?

Tout d'abord, vous devez vous mettre en tête que peu importe la taille de votre site, un attaquant sera éventuellement capable de :

  • Récupérer les informations de votre base de données
  • Avoir accès au code source du serveur
  • Automatiser des actions pour essayer de s'introduire

Bien sûr, votre objectif est de tout faire pour éviter que cela arrive, mais il faut que vous gardiez ces informations en tête lors de la conception de votre système de mots de passe.

Communiquer en https

La première étape est de sécuriser votre site web (ou votre application) en forçant la communication par https car lors de l'inscription ou de la connexion, le mot de passe de votre utilisateur sera envoyé en clair dans la requête.

Pour éviter tout problème d'interception des données, assurez vous que le chiffrement de ces données soit effectué grâce à un certificat SSL, c'est la première étape de sécurisation du mot de passe.

Hashage

Une fois arrivé sur le serveur, le mot de passe devra être "hashé" avant d'être sauvegardé en base de données. Attention, on ne chiffre (encrypte) pas le mot de passe, mais on le hash, les deux notions sont complètement différentes.

Une donnée chiffrée doit pouvoir être déchiffrée grâce à la clé de chiffrement utilisée et l'on doit pouvoir retrouver l'information originelle intacte.

Le hashage consiste à faire passer une donnée d'une taille arbitraire dans une fonction qui va la transformer en une donnée d'une taille définie, en générale une taille plus grande pour les mots de passe.

Contrairement au chiffrement, une fonction de hashage est destructive (ou unilatéral) car on perd de la donnée d'origine, il est impossible de revenir en arrière.

Pourquoi le hashage ?

Prenons une fonction de hashage théorique la plus simple possible, disons que notre fonction prend une chaine de caractère en entrée, et retourne sa taille :

f(x) => taille(x)

Ce qui nous donne "bonjour" => 7, "password" => 8 et "chien" => 5

On voit bien ici qu'une fois passé dans la fonction, le mot de passe n'est plus récupérable, donc si on le stocke dans une base de données, il est "protégé".

Impossible de récupérer le mot "bonjour" à partir du simple chiffre 7

Pour la connexion, il suffira de hasher en direct le mot de passe fourni par l'utilisateur et le comparer au hash stocké dans la base, car la fonction de hashage doit toujours retourner le même hash pour la même donnée en entrée.

Quel algorithme ?

Vous l'aurez compris, le problème avec notre fonction de hashage simplifiée, ce sont les collisions. Car en l'occurence, le hash de "bonjour" est égal à 7 mais le hash de "baisers" est aussi égal à 7, c'est ce que l'on appelle une collision, est c'est l'une des problématiques du hashage.

En pratique, les fonctions de hashage cryptographique génère des hash souvent beaucoup plus longs que la valeur d'entrée, par exemple le hash du mot "bonjour" avec l'algorithme SHA-256 est égale à :

2cb4b1431b84ec15d35ed83bb927e27e8967d75f4bcd9cc4b25c8d879ae23e18

alors que le hash du mot "baisers" est égal à :

73beed7425bd31551890c0727f4b169cd99b5c708fa8d50a713747e0878e2580

La complexité d'une algorithme de hashage réside dans son ratio entre le temps d'exécution et le nombre de collisions possibles, par exemple la famille d'algorithme SHA est très rapide à s'exécuter, mais son nombre de collision possible est plus élevé que d'autres algorithme comme le Bcrypt.

À moins que la contrainte de temps d'exécution soit une grosse problématique (rarement le cas pour du hashage de mot de passe, car le temps d'exécution reste minime), il est recommandé d'utiliser l'algorithme BCrypt.

Si vous voulez en apprendre plus au sujet de ce dernier, il y a un très bon article sur le blog de Auth0 que je vous recommande !

Grain de sel

À première vue, lorsque vos mots de passe sont hashés avec un algorithme suffisamment sécurisé, même si votre base de données subit une fuite, les attaquants n'auront pas directement accès aux mots passe de clairs.

Mais si ces dernier arrivent à découvrir quel algorithme de hashage a été utilisé (ce qui est possible), il leur reste quand même la possibilité de générer des mots de passe et de les comparer aux hashs trouvés en utilisant des techniques comme  :

  • Le brut-force: Tester toutes les possibilités de suites de caractères différents
  • Les dictionnaires : Tester des combinaisons de mots issus des informations personnels et de mots usuels

Certains attaquants utilisent même ce qu'on appelle des "rainbow-table", d'immenses tableaux de hashs déjà générés (avec les méthodes ci-dessus) avec l'algorithme de hashage trouvé précédemment, ces tableaux peuvent parfois peser jusqu'à plusieurs Tera-octets.

Pour freiner (voir empêcher) ces attaques, on utilise la méthode du grain de sel (ou du salage) qui consiste à ajouter une chaine de caractères au mot de passe avant qu'il ne soit hashé.

Ce grain de sel permet de rallonger la taille du mot de passe de base (et donc de le rendre plus long à craquer, car plus long à générer), et de limiter l'utilisation de dictionnaires et des rainbow-tables.

Statique

Le salage statique consiste à ajouter toujours la même chaine de caractères pour tous les mots de passe enregistrés, ce grain de sel doit rester secret, car sinon son efficacité est corrompue.

Cette technique permet de ralentir la récupération des mots de passe, mais elle n'empêche pas l'utilisation de rainbow-tables, ces dernières devront simplement être générées spécifiquement pour ce site en particulier.

Dynamique

Le salage dynamique consiste à générer aléatoirement un grain de sel pour chaque utilisateur, et de le stocker en plus du mot de passe dans la base de donnée (ou au mieux dans une base de donnée séparée).

Cette technique vise notamment à empêcher l'utilisation d'une rainbow-table sur l'entièreté de la base de données, car chaque utilisateur ayant un grain de sel différent, il est impossible de pré-calculer tous les hashs pour tous les grains de sels possibles.

J'espère que cet article vous aura été utile, et à bientôt sur le blog !

Les articles les plus populaires du blog

Envie de continuer à lire des articles autour du développement web (entre autres) ? Voici la sélection des articles de mon blog les plus lus par la communauté !

Voir la sélection 🚀

Recevez les articles de la semaine par e-mail pour ne rien manquer !

S'abonner à la newsletter 📧

À propos de l'auteur

Hello, je suis Nicolas Brondin-Bernard, ingénieur web indépendant depuis 2015 passionné par le partage d'expériences et de connaissances.

Aujourd'hui je suis aussi coach pour développeurs web juniors, tu peux me contacter sur nicolas@brondin.com, sur mon site ou devenir membre de ma newsletter pour ne jamais louper le meilleur article de la semaine et être tenu au courant de mes projets !


Photo par Markus Spiske sur Unsplash