Authentication

Hachage de mots de passe

Les mots de passe sont le seul secret que vous ne devriez jamais stocker. Un hachage lent et salé transforme une base de données volée en un tas de tentatives qui ne s'achèvent jamais.

intermediate14 min readUpdated 20 sept. 2026
passwords.js
js
// passwords.js
import { hash, verify } from "@node-rs/argon2";

export const hashPassword = (password) => hash(password);

export async function verifyPassword(password, stored) {
  try {
    return await verify(stored, password);
  } catch {
    return false;
  }
}
Règle
Hacher, jamais chiffrer
Sel
Unique par mot de passe
Recommandé
Argon2id
Encore courant
bcrypt
Comparaison
Timing-safe
Au login
Rehash si nécessaire

Pourquoi c'est important

Pourquoi le hachage n'est pas optionnel

Unidirectionnel par conception

Un hachage de mot de passe ne peut pas être inversé ; ainsi, une table fuitée ne révèle aucun texte en clair et l'attaquant est forcé de procéder par tentatives hors ligne.

Le sel combat la précomputation

Un sel aléatoire unique par mot de passe rend les rainbow tables inutiles et garantit que deux mots de passe identiques produisent des hachages différents.

Le coût est l'objectif

Un facteur de travail rend chaque tentative suffisamment lente pour que la force brute devienne impraticable, et ce coût peut être augmenté à mesure que le matériel s'accélère.

Le tableau complet

Les trois piliers d'identifiants sécurisés

Hacher, jamais chiffrer ; saler chaque condensat ; et rendre chaque tentative délibérément coûteuse.

Hacher

Transformer

Une fonction de dérivation de clé transforme le mot de passe en un condensat de longueur fixe qui ne peut être inversé.

Saler

Randomiser

Une valeur aléatoire stockée à côté du condensat rend chaque hachage unique et neutralise les tables précomputées.

Vérifier

Comparer

Lors de la connexion, redérivez et comparez en temps constant, puis mettez à jour le hachage si les paramètres sont obsolètes.

HTML5 en un coup d'oeil

À quoi ressemble un stockage d'identifiants robuste

Argon2id

Le standard moderne, avec mémoire, itérations et parallélisme ajustables.

bcrypt

Éprouvé et intégré dans la plupart des stacks, avec un facteur de coût et une limite de 72 octets.

scrypt

Memory-hard et standardisé, un bon choix quand Argon2 n'est pas disponible.

Sel

Aléatoire par mot de passe et stocké dans la même chaîne que le condensat.

Comparaison timing-safe

Comparer les condensats sans fuite d'informations via une sortie anticipée.

Rehash au login

Augmenter le coût ou changer d'algorithme au moment où les utilisateurs se connectent.

Un bref aperçu

De crypt aux hachages memory-hard

  1. 1979

    crypt et DES

    Les premiers systèmes Unix hachent les mots de passe avec une variante DES à 25 rounds et un sel de 12 bits.

    79
  2. 1999

    bcrypt

    Provos et Mazieres introduisent un hachage adaptatif basé sur Blowfish avec un coût ajustable.

    99
  3. 2012

    scrypt

    Une fonction memory-hard est publiée pour rendre le cracking parallèle à grande échelle coûteux.

    12
  4. 2015

    Argon2 gagne la PHC

    Argon2id est sélectionné comme vainqueur de la Password Hashing Competition.

    15
  5. Aujourd'hui

    Adaptatif par défaut

    Les frameworks proposent Argon2 ou bcrypt et s'attendent à ce que vous ajustiez le facteur de travail.

    Aujourd'hui

Le guide complet

Hachage de mots de passe: Tout ce que vous devez savoir

Pourquoi les mots de passe nécessitent un traitement particulier

Tous les autres secrets de votre système peuvent être renouvelés : clés API, tokens, certificats. Les mots de passe sont différents. Vous ne les détenez jamais sous une forme permettant de les régénérer, les utilisateurs les réutilisent sur plusieurs sites, et dès que votre base de données fuite, l’attaquant a tout le temps nécessaire pour tenter de les deviner hors ligne.

Le hachage de mot de passe consiste à stocker une transformation unidirectionnelle du mot de passe au lieu du mot de passe lui-même. Lorsqu’un utilisateur se connecte, vous appliquez la même transformation et comparez les résultats. Vous ne connaissez jamais le mot de passe, et quiconque volerait la table ne le connaîtrait pas non plus.

Ce n’est pas le moment de vouloir être original. Les règles sont simples et bien établies, et c’est en les transgressant que les failles de sécurité deviennent catastrophiques.

Le hachage n’est pas du chiffrement

Le chiffrement est réversible. Si vous chiffrez les mots de passe, la clé se trouve quelque part dans votre système, et toute personne qui y accède — via une fuite, une sauvegarde, une variable d’environnement mal configurée ou un initié — peut lire tous les mots de passe d’un coup. Il n’existe aucun scénario où vous avez besoin du mot de passe original, donc la réversibilité représente un risque pur.

Une fonction de hachage prend une entrée et produit un condensat (digest) de longueur fixe, et il n’existe aucun moyen pratique de revenir en arrière. Pour les mots de passe, un hachage simple ne suffit toujours pas : les fonctions rapides comme SHA-256 sont conçues pour être véloces, ce qui est précisément ce qu’un attaquant recherche. Un GPU peut tester des milliards de combinaisons par seconde.

Vous avez besoin d’une fonction qui soit délibérément lente et memory-hard, afin que les tentatives de devinette soient coûteuses à grande échelle.

Salt : même mot de passe, hash différent

Sans salt, deux utilisateurs ayant le mot de passe hunter2 produiront le même condensat (digest). Un attaquant peut précalculer un tableau géant de mots de passe courants et de leurs hashs — une rainbow table — et trouver des correspondances instantanément. Il peut également voir d’un coup d’œil quels comptes partagent le même mot de passe.

Un salt (ou grain de sel) est une valeur aléatoire unique générée pour chaque mot de passe et stockée aux côtés du condensat. Ce n’est pas un secret ; son seul rôle est de rendre chaque hash unique. Désormais, l’attaquant doit s’attaquer à chaque compte séparément, et le précalcul devient inutile.

Anatomy of a stored Argon2 hash
$argon2id$v=19$m=19456,t=2,p=1$c29tZXNhbHQ$aBc...
algorithm + paramsalgorithm, version and work factors
saltunique per password, not secret
digestthe derived key you compare against

Les bibliothèques modernes génèrent le salt pour vous et l’encodent, avec les paramètres, dans une seule et même chaîne de caractères. Il vous suffit de stocker cette chaîne telle quelle.

Choisir un algorithme

Trois fonctions valent la peine d’être connues. Elles sont toutes adaptatives : le coût peut être augmenté à mesure que le matériel s’améliore.

Argon2id

Le vainqueur de la Password Hashing Competition de 2015 et la recommandation actuelle. Il est “memory-hard”, ce qui signifie qu’un attaquant doit investir dans la mémoire autant que dans la puissance de calcul, réduisant ainsi l’avantage des GPU et des ASIC. Argon2id équilibre la résistance aux attaques par canal auxiliaire et aux attaques GPU, et constitue le choix par défaut idéal pour les nouveaux systèmes.

scrypt

Standardisé dans la RFC 7914 et également “memory-hard”, scrypt est un choix solide lorsque Argon2 n’est pas disponible. Il expose le coût, la taille des blocs et le parallélisme, ce qui permet de l’ajuster, mais ses paramètres sont plus faciles à mal configurer que ceux d’Argon2.

bcrypt

Sorti en 1999 et encore omniprésent, bcrypt est bien compris et éprouvé. Son facteur de coût double la charge de travail à chaque incrément. Le principal bémol est qu’il tronque l’entrée à 72 octets, donc les phrases de passe très longues sont silencieusement coupées — effectuez un pré-hash si cela est important pour vous.

Quel que soit votre choix, n’utilisez jamais MD5, SHA-1 ou SHA-256 pur. Ce ne sont pas les bons outils, et empiler des itérations par-dessus constitue un schéma artisanal en lequel personne ne devrait avoir confiance.

Ajuster le facteur de travail (work factor)

Le coût doit équilibrer deux contraintes. S’il est trop bas, le hash devient vulnérable aux attaques par force brute ; s’il est trop élevé, un pic de tentatives de connexion peut se transformer en vecteur de déni de service (DoS) contre votre propre CPU.

Ajustez-le pour qu’un seul hash prenne environ 100 à 500 millisecondes sur votre matériel de production. Mesurez le point de terminaison (endpoint) de connexion sous une charge réaliste, et non via une simple boucle de benchmark, puis fixez cette valeur en vous basant sur vos données. Revoyez ensuite ce paramètre périodiquement : à paramètres égaux, la sécurité s’affaiblit chaque année à mesure que le matériel s’améliore.

// Argon2id parameters (memory in KiB, iterations, parallelism)
await hash(password, { memoryCost: 19456, timeCost: 2, parallelism: 1 });

Stockage et vérification

L’inscription et la connexion sont les deux seuls endroits où vous manipulez un mot de passe.

import { hash, verify } from "@node-rs/argon2";

// Registration: hash before the password ever reaches the database.
const digest = await hash(password);
await db.users.insert({ email, passwordHash: digest });

// Login: verify against the stored digest.
const user = await db.users.findByEmail(email);
const ok = user && (await verify(user.passwordHash, password));
if (!ok) return res.status(401).json({ error: "invalid_credentials" });

Renvoyez la même erreur, que l’e-mail ou le mot de passe soit incorrect. Un message tel que « utilisateur inexistant » permettrait à un attaquant d’énumérer les comptes.

Attaques temporelles et comparaison sécurisée

Comparer deux hashs avec === s’arrête au premier octet différent. Le temps d’exécution dépend donc de la partie correcte de la tentative, et un attaquant patient peut mesurer cet écart pour reconstruire une valeur. C’est un canal étroit, mais la comparaison de mots de passe est précisément l’endroit où cela devient critique.

Utilisez la fonction de vérification de la bibliothèque, qui effectue la comparaison en temps constant. Ne comparez jamais les digests vous-même, et ne comparez jamais le mot de passe en clair.

Mettre à jour les hashs au fil du temps

Vos besoins évolueront : le coût de calcul augmentera, ou vous migrerez de bcrypt vers Argon2. Comme vous n’avez jamais stocké le mot de passe en clair, vous ne pouvez effectuer le rehash qu’au moment de la connexion, lorsque le mot de passe se trouve brièvement en mémoire.

Stockez l’algorithme et les paramètres avec chaque digest — la chaîne encodée le fait déjà — et vérifiez-les à chaque connexion réussie :

if (await verify(stored, password)) {
  if (needsRehash(stored)) {
    await db.users.update(user.id, { passwordHash: await hash(password) });
  }
  // continue the login
}

Les utilisateurs qui ne se connectent plus conservent leur ancien hash, ce qui ne pose aucun problème ; ils restent protégés. Au fil du temps, les comptes actifs migrent naturellement.

La politique de mots de passe en pratique

L’algorithme vous protège après une faille. La politique réduit la probabilité qu’une faille survienne.

  • Privilégiez la longueur plutôt que la complexité. Une phrase de passe est plus efficace qu’P@ssw0rd!.
  • Vérifiez les nouveaux mots de passe par rapport aux listes de fuites connues, comme l’API k-anonymity de Have I Been Pwned.
  • N’imposez pas de rotation arbitraire. L’expiration forcée conduit à des schémas de type Summer2026!.
  • Limitez le nombre de tentatives de connexion et de réinitialisation (rate-limiting), et ajoutez un backoff exponentiel ou un verrouillage du compte.
  • Utilisez un flux de réinitialisation générique avec des jetons à usage unique et à expiration limitée, et n’envoyez jamais de mot de passe par e-mail.

Bonnes pratiques

  • Utilisez Argon2id, scrypt ou bcrypt pour le hachage — jamais un algorithme de hachage généraliste rapide.
  • Laissez la bibliothèque générer et stocker le sel (salt).
  • Ajustez le coût pour obtenir un temps de traitement entre 100 et 500 ms, et augmentez-le progressivement avec le temps.
  • Effectuez la vérification avec la fonction en temps constant de la bibliothèque.
  • Re-hachez le mot de passe lors d’une connexion réussie si les paramètres ont changé.
  • Retournez des erreurs génériques et limitez le nombre de tentatives (rate-limiting).
  • Effectuez le hachage côté serveur ; jamais côté client.

Erreurs courantes

  • Chiffrer les mots de passe ou les stocker en texte brut « temporairement ».
  • Utiliser SHA-256 ou MD5 avec seulement quelques itérations et appeler cela du hachage.
  • Utiliser un sel global unique, ou réutiliser le même sel pour plusieurs comptes.
  • Comparer des hashs avec == ou ===.
  • Journaliser les mots de passe ou les inclure dans des rapports d’erreur.
  • Limiter la longueur des mots de passe à une valeur trop basse, ce qui pénalise les phrases de passe.
  • Oublier de mettre à jour le facteur de coût pendant plusieurs années.

Et après ?

Les identifiants ne sont que la première étape. Une fois l’utilisateur vérifié, vous devez pouvoir conserver cet état : consultez le guide sur Session Auth pour les sessions basées sur les cookies, ou le guide JWT pour les jetons sans état (stateless). Si vous préférez ne pas gérer les mots de passe du tout, OAuth 2.0 et OpenID Connect permettent de déléguer l’authentification à un fournisseur d’identité.

En pratique

Hacher, stocker, vérifier

Les trois mêmes étapes pour chaque stack. La bibliothèque gère le sel et l'encode aux côtés du condensat.

hash.js
import { hash } from "@node-rs/argon2";

const digest = await hash(password);
// $argon2id$v=19$m=19456,t=2,p=1$...$...

Hacher un mot de passe

Utilisez un hachage conçu pour les mots de passe avec un facteur de travail. Un hachage rapide à usage général est le cadeau préféré des crackers.

Préférer
import { hash } from "@node-rs/argon2";

const digest = await hash(password);
Éviter
import { createHash } from "node:crypto";

const digest = createHash("sha256")
  .update(password)
  .digest("hex");

Comparer un mot de passe

Comparez via la vérification en temps constant de la bibliothèque. Une égalité de chaîne simple peut fuiter le contenu et la longueur via le timing.

Préférer
const ok = await verify(stored, password);
Éviter
const ok = stored === (await hash(password));

Compromis

Argon2 ou bcrypt ?

Les deux sont sûrs s'ils sont bien configurés. Argon2 est le standard moderne ; bcrypt reste un excellent choix avec des années d'utilisation en production.

Strengths

  • Argon2id est memory-hard

    Il résiste au cracking par GPU et ASIC en exigeant de la mémoire en plus du temps, et c'est la recommandation actuelle.

  • bcrypt est omniprésent

    Il est intégré dans la plupart des frameworks, possède un long historique et ne nécessite aucune dépendance native supplémentaire.

  • Les deux sont ajustables

    Le facteur de travail peut être augmenté avec le temps, permettant de renforcer les hachages stockés sans changer les mots de passe des utilisateurs.

Trade-offs

  • bcrypt tronque à 72 octets

    Les phrases de passe longues sont silencieusement coupées ; pré-hachez ou préférez Argon2 si cela est critique.

  • Le réglage demande de la prudence

    Trop bas, c'est crackable ; trop haut, la connexion devient un vecteur de déni de service (DoS) sous charge.

  • Le hachage n'est pas tout

    Le rate limiting, la vérification des fuites et un flux de réinitialisation sécurisé sont tout aussi importants que l'algorithme.

FAQ

Foire aux questions

Keep learning

Related topics from the roadmap.

$ commencer à apprendre

Prêt à apprendre Password Hashing & Credentials ?

Notre tutoriel interactif vous guide à travers Password Hashing & Credentials pas à pas — avec des quiz et du vrai code que vous pouvez exécuter dans le navigateur.