La gestion des mots de passe utilisateur reste l’un des piliers fondamentaux de la sécurité d’une application. Une faille dans ce système peut conduire à des fuites de données massives, une perte de confiance irrémédiable et des conséquences juridiques sévères. Pourtant, de nombreuses applications reproduisent encore des pratiques obsolètes et dangereuses. Cet article détaille les bonnes pratiques modernes à implémenter côté serveur pour stocker et vérifier les mots de passe de manière robuste et résiliente.
L’impératif absolu : ne jamais stocker les mots de passe en clair
C’est la règle numéro un, non négociable. Votre base de données ne doit jamais contenir le mot de passe original (en clair) saisi par l’utilisateur. En cas de compromission de la base (par une injection SQL, une fuite de backup, etc.), les attaquants obtiendraient immédiatement l’accès à tous les comptes.
La solution ? Le hachage (hashing). Il s’agit d’une fonction mathématique à sens unique qui transforme le mot de passe en une chaîne de caractères fixe (un « hash » ou « empreinte »). Il doit être impossible de retrouver le mot de passe original à partir de cette empreinte. Lors de la connexion, vous hachez simplement le mot de passe fourni et comparez l’empreinte avec celle stockée.
Le hachage simple est mort : vive les fonctions lentes et salées

Utiliser une fonction de hachage rapide comme MD5 ou SHA-1 (ou même SHA-256 dans ce contexte) est aujourd’hui considéré comme une faute grave. Ces algorithmes sont conçus pour être rapides, ce qui les rend vulnérables aux attaques par force brute et aux rainbow tables (des tables pré-calculées d’empreintes pour des millions de mots de passe courants). Pour explorer en profondeur, cliquez ici.
Pour contrer cela, on utilise des fonctions de hachage adaptatives et lentes (key derivation functions) :
1. Le salage (Salt) : l’unicité comme bouclier
Un salt est une valeur aléatoire unique générée pour chaque utilisateur et ajoutée à son mot de passe avant le hachage. Ce simple principe rend les rainbow tables totalement inutiles, car une même table ne peut pas servir pour deux utilisateurs différents.
-
Génération : Utilisez un générateur cryptographique sécurisé pour créer un salt long (≥ 16 octets).
-
Stockage : Stockez le salt en clair à côté du hash. Sa divulgation n’est pas un problème de sécurité en soi, car son rôle est justement d’être public mais unique.
2. Les fonctions modernes : bcrypt, Argon2, scrypt
Ces algorithmes intègrent nativement le concept de salage et, surtout, sont intentionnellement lents et coûteux en ressources (CPU, mémoire). Cela rend les attaques par force brute extrêmement longues et chères, même pour des mots de passe faibles.
-
bcrypt : Un vétéran robuste, largement supporté. Il permet de définir un facteur de coût (work factor) qui augmente la lenteur du calcul, permettant de s’adapter à la puissance matérielle future.
-
Argon2 : Vainqueur du Password Hashing Competition en 2015, c’est l’algorithme recommandé aujourd’hui. Sa grande force est d’être également coûteux en mémoire (memory-hard), ce qui rend les attaques par matériel spécialisé (ASIC, GPU) bien moins efficaces. Préférez Argon2id, un hybride résistant aux attaques par canaux auxiliaires.
-
scrypt : Similaire à Argon2 dans son approche memory-hard, également très sécurisé.
En pratique : N’implémentez jamais vous-même la logique de salage et d’itérations. Utilisez toujours la bibliothèque standard ou des librairies cryptographiques éprouvées de votre langage, qui proposent des interfaces simples pour ces fonctions.
Le processus pas à pas : de l’inscription à l’authentification
À l’inscription (Registration) :
-
L’utilisateur choisit un mot de passe.
-
Le serveur génère un salt unique.
-
Le serveur hache le mot de passe avec le salt et une fonction adaptative (ex: Argon2id) en définissant des paramètres de coût adaptés à votre matériel.
-
Il stocke dans la base le couple
(hash_resultat, salt, identifiant_algorithme).
À la connexion (Authentication) :
-
L’utilisateur envoie son identifiant et son mot de passe tentatif.
-
Le serveur récupère le hash stocké, le salt et l’identifiant de l’algorithme pour cet utilisateur.
-
Il hache le mot de passe tentatif avec le salt récupéré et les mêmes paramètres d’algorithme.
-
Il compare les deux hashs avec une fonction de comparaison à temps constant (pour éviter les attaques par timing). Si ils sont identiques, l’accès est accordé.
Les autres pratiques de sécurité indispensables
Imposer une politique de mots de passe raisonnable
Oubliez les règles complexes (un chiffre, une majuscule, un symbole). Elles génèrent des mots de passe prévisibles (Motdepasse1!). Suivez plutôt les recommandations du NIST :
-
Longueur minimale (ex: 12 caractères). C’est le facteur le plus important.
-
Vérification contre les listes de mots de passe compromis : Votre application doit refuser les mots de passe figurant dans des bases de données de fuites connues (comme
Have I Been Pwnedvia son APIPwned Passwords). -
Pas de règles de composition contraignantes ou de rotation périodique imposée.
Prévenir les attaques par force brute côté serveur
Même avec un hash robuste, il faut protéger le point d’entrée.
-
Mise en œuvre d’un rate limiting : Limitez le nombre de tentatives de connexion par adresse IP et/ou par compte sur une fenêtre de temps (ex: 5 échecs en 15 minutes).
-
Mise en place d’un délai d’attente progressif (exponential backoff) : Après plusieurs échecs, imposez un délai croissant avant une nouvelle tentative, ce qui ralentit considérablement une attaque automatisée.
Ne jamais renvoyer d’indices dans les messages d’erreur
Les messages comme « mot de passe incorrect » ou « nom d’utilisateur invalide » aident un attaquant à énumérer les comptes existants. Utilisez un message générique : « Identifiants incorrects« .
Proposer et favoriser l’authentification à deux facteurs (2FA/ MFA)
Pour les comptes sensibles, le mot de passe seul ne devrait pas suffire. Proposez et encouragez l’ajout d’un second facteur d’authentification (application d’authentification comme Google Authenticator, clé de sécurité physique de type FIDO2/WebAuthn). En cas de fuite du hash, le compte reste protégé.
Un investissement critique et non-négociable
La sécurité des mots de passe côté serveur n’est pas une fonctionnalité avancée, mais un prérequis fondamental. En résumé :
-
Hachez TOUS les mots de passe avec une fonction adaptative moderne (Argon2id, bcrypt).
-
Utilisez un salt unique par utilisateur.
-
Ajustez les paramètres de coût pour que le hachage reste lent (≥ 500 ms) sur votre matériel.
-
Implémentez un rate limiting sur les endpoints de connexion.
-
Vérifiez les nouveaux mots de passe contre les listes de fuites connues.
-
Planifiez la migration progressive des anciens hashs faibles vers un algorithme moderne lors des prochaines connexions.
Investir dans cette stack de sécurité est la meilleure garantie pour protéger vos utilisateurs, même en cas de fuite de données. C’est une responsabilité technique et éthique qui doit faire partie des fondations de toute application.