ITSkillsCenter
Cybersécurité

Hasher des mots de passe avec bcrypt et argon2 pas-à-pas — Node.js, Python et PHP

8 min de lecture

Stocker des mots de passe utilisateurs en clair, en MD5 ou en SHA-1 est une faute professionnelle qui transforme la moindre fuite de base de données en catastrophe pour les utilisateurs. Le hachage moderne — bcrypt, scrypt, argon2 — ralentit volontairement le calcul pour rendre les attaques par force brute irréalistes. Ce tutoriel propose une démarche en six étapes pour implémenter correctement le hachage de mots de passe en Node.js, Python et PHP — les trois piles les plus utilisées sur les hébergements abordables disponibles en Afrique de l’Ouest.

Pour la vue d’ensemble cryptographie, voir le guide principal : Cryptographie pratique pour développeurs et sysadmins.

Prérequis

  • Une application web avec authentification utilisateur (existante ou en projet)
  • Node.js 18+, Python 3.10+ ou PHP 8.2+ selon la pile
  • Un environnement de développement local fonctionnel
  • 30 minutes pour comprendre, implémenter et tester

Étape 1 — Choisir entre bcrypt et argon2

Les deux algorithmes sont actuellement recommandés par OWASP pour le stockage de mots de passe. Le choix se résume à deux critères. argon2id est le gagnant du Password Hashing Competition de 2015, plus récent, recommandé pour les nouveaux projets. bcrypt est l’algorithme de référence depuis 1999, largement déployé et éprouvé — il reste acceptable et toutes les bibliothèques web modernes le supportent.

Règle pratique : pour un nouveau projet en 2026, choisir argon2id si la bibliothèque est facilement disponible dans le langage. Pour migrer un projet existant, ne pas perdre de temps à passer de bcrypt à argon2 sans raison forte — bcrypt fonctionne et reste sécurisé. Dans tous les cas, ne jamais utiliser MD5, SHA-1, SHA-256 ou SHA-512 seuls : ils sont rapides et donc cassables en quelques heures sur un GPU contemporain.

Étape 2 — Implémentation Node.js avec bcrypt

La bibliothèque bcrypt sur npm est la référence. Elle wrappe le code natif C++ pour des performances correctes. Installer :

npm install bcrypt

Le module installe une dépendance native compilée à l’installation — pas d’inquiétude, c’est normal. Une alternative pure JavaScript existe (bcryptjs) si on rencontre des problèmes de compilation, plus lente mais identique fonctionnellement.

Le code minimal pour hasher à l’inscription et vérifier à la connexion :

const bcrypt = require('bcrypt');
const SALT_ROUNDS = 12;

async function hashPassword(plainPassword) {
  return await bcrypt.hash(plainPassword, SALT_ROUNDS);
}

async function verifyPassword(plainPassword, storedHash) {
  return await bcrypt.compare(plainPassword, storedHash);
}

La constante SALT_ROUNDS contrôle la lenteur du hachage : 12 est le bon compromis en 2026 sur un serveur moderne (environ 200 à 300 ms par hachage). Augmenter à 13 ou 14 sur un serveur très rapide ; descendre à 10 seulement sur du matériel très limité. Le sel est généré automatiquement par bcrypt à chaque hachage et inclus dans la chaîne stockée — pas besoin de le gérer séparément.

Le résultat est une chaîne de 60 caractères commençant par $2b$12$, à stocker dans la colonne password_hash de la table utilisateurs. Le mot de passe en clair n’est jamais stocké, jamais journalisé, jamais transmis ailleurs.

Étape 3 — Implémentation Python avec argon2

La bibliothèque argon2-cffi est l’implémentation Python de référence. Elle est utilisée par Django depuis la version 1.10 comme algorithme par défaut. Installer :

pip install argon2-cffi

Le code minimal pour hasher et vérifier :

from argon2 import PasswordHasher
from argon2.exceptions import VerifyMismatchError

ph = PasswordHasher()

def hash_password(plain_password: str) -> str:
    return ph.hash(plain_password)

def verify_password(plain_password: str, stored_hash: str) -> bool:
    try:
        ph.verify(stored_hash, plain_password)
        return True
    except VerifyMismatchError:
        return False

Les paramètres par défaut de PasswordHasher() sont conformes aux recommandations OWASP 2026 (variant argon2id, time_cost=3, memory_cost=64 MB, parallelism=4). Pas besoin de les modifier sauf cas particuliers.

Le hash résultant est une chaîne d’environ 95 caractères commençant par $argon2id$v=19$. Le sel est inclus, pas besoin de le gérer. Pour Django, l’authentification utilise déjà argon2 par défaut — il suffit de l’inclure dans PASSWORD_HASHERS dans settings.py sans rien implémenter manuellement.

Étape 4 — Implémentation PHP avec password_hash()

PHP fournit depuis la version 5.5 une API native qui s’occupe de tout : choix de l’algorithme, génération du sel, choix du facteur de coût. Sur PHP 8.2+, l’API supporte argon2id en plus de bcrypt, et les paramètres par défaut sont à jour.

Le code minimal :

// Hasher (à l'inscription)
$hash = password_hash($plainPassword, PASSWORD_DEFAULT);

// Vérifier (à la connexion)
if (password_verify($plainPassword, $storedHash)) {
    // Authentification réussie
}

La constante PASSWORD_DEFAULT pointe vers l’algorithme recommandé du moment — bcrypt sur PHP 5.5 à 7.4, et toujours bcrypt par défaut en PHP 8.2 (le passage à argon2 par défaut a été plusieurs fois discuté mais n’a pas eu lieu). Pour forcer argon2id explicitement :

$hash = password_hash($plainPassword, PASSWORD_ARGON2ID);

L’avantage de PASSWORD_DEFAULT : si une future version de PHP change l’algorithme par défaut, le code utilise automatiquement le nouveau sans modification — à condition d’utiliser aussi password_needs_rehash() au moment de la connexion pour migrer les anciens hashs.

Étape 5 — Migrer une base existante en MD5 ou SHA-1

Beaucoup d’applications anciennes stockent encore des hashs MD5 ou SHA-1. La migration ne peut pas se faire en lot — les hashs anciens sont irréversibles, on ne peut pas les recalculer en argon2 sans les mots de passe en clair. La méthode propre passe par une migration progressive à la connexion suivante de chaque utilisateur.

Algorithme : à la connexion, vérifier le mot de passe en clair contre l’ancien hash MD5/SHA-1. Si OK, immédiatement re-hasher avec argon2 et remplacer en base. Au bout de quelques mois, la majorité des utilisateurs actifs aura migré. Pour les comptes inactifs, désactiver après une période raisonnable (six mois par exemple) ou demander un renouvellement de mot de passe forcé.

Pendant la phase de transition, ajouter en base une colonne password_algo qui indique md5, sha1, bcrypt ou argon2id — la logique de connexion choisit la bonne fonction de vérification selon la valeur. Une fois la migration terminée, supprimer la colonne et la logique de fallback.

Étape 6 — Tester l’implémentation

Trois tests minimaux confirment que l’implémentation est correcte. Le test hash + verify identiques : hasher un mot de passe, vérifier la chaîne avec le bon mot de passe — doit retourner vrai. Le test verify avec mauvais mot de passe : la même chaîne avec un mot de passe différent — doit retourner faux. Le test hash deux fois différents : hasher le même mot de passe deux fois et vérifier que les chaînes résultantes sont différentes (sels distincts) mais que les deux vérifient bien le mot de passe original.

Mesurer aussi le temps d’un hachage. En 2026 sur un serveur moderne, viser environ 200-300 ms. Trop rapide (moins de 50 ms) signale un facteur de coût trop bas — augmenter SALT_ROUNDS en bcrypt ou time_cost en argon2. Trop lent (plus de 1 seconde) bloque la connexion utilisateur — descendre les paramètres.

Vérification du livrable

  • Aucun mot de passe n’est stocké en clair dans la base ou les logs
  • L’algorithme utilisé est bcrypt ou argon2id (jamais MD5, SHA-1, SHA-256 seul)
  • Le facteur de coût produit un hachage en 200-300 ms
  • Les sels sont gérés automatiquement par la bibliothèque (pas codés à la main)
  • Une stratégie de migration des anciens hashs est en place si nécessaire

Erreurs fréquentes

ErreurConséquenceSolution
SHA-256 sans selCassable en quelques heures avec rainbow tablesbcrypt ou argon2id
Sel codé en dur dans l’applicationTous les hashs cassables ensembleSel généré aléatoirement par hash
Mot de passe loggé en clairFuite via fichiers de logsFiltrer les paramètres password dans les logs
SALT_ROUNDS = 4 ou 6Hachage trop rapide, brute force possible12 minimum en 2026
Pas de re-hash à la migrationAnciens hashs MD5 jamais éliminésRe-hash automatique à la prochaine connexion

Versions PHP des hébergeurs sénégalais

Trois ajustements pratiques pour une mise en œuvre locale. La compatibilité hébergeur : Hostinger, OVH et Sonatel hébergement supportent toutes les versions de PHP 7.4+ et permettent argon2id sans configuration spéciale ; pour les hébergeurs très entrée de gamme parfois bloqués sur PHP 7.0 ou 7.2, bcrypt reste la voie sûre. La politique de mots de passe à la création de compte doit imposer un minimum réaliste — 8 à 12 caractères, au moins une lettre et un chiffre — sans bloquer les utilisateurs sur des règles trop strictes qui les pousseraient vers P@ssw0rd1, particulièrement contre-productif quand l’audience inclut des utilisateurs peu familiers du clavier QWERTY. Le second facteur (TOTP via Google Authenticator) protège mieux que toute politique de mots de passe — à proposer en option pour les comptes sensibles, et à imposer pour les accès administrateur.

Tutoriels frères

Pour aller plus loin

Sources et références

Besoin d'un site web ?

Confiez-nous la Création de Votre Site Web

Site vitrine, e-commerce ou application web — nous transformons votre vision en réalité digitale. Accompagnement personnalisé de A à Z.

À partir de 250.000 FCFA
Parlons de Votre Projet
Publicité