
Hachage de mots de passe avec Bcrypt : pourquoi c'est important et comment l'utiliser
📷 Pixabay / PexelsHachage de mots de passe avec Bcrypt : pourquoi c'est important et comment l'utiliser
Les mots de passe stockés sous forme de hachages SHA-256 peuvent être craqués en quelques minutes. Bcrypt est conçu pour être lent -- et c'est précisément le but. Découvrez comment bcrypt fonctionne, comment choisir un facteur de coût, et comment l'implémenter en Node.js, Python et PHP.
Le problème du stockage des mots de passe
Imaginez que vous construisez un système de connexion. Un utilisateur crée un compte avec le mot de passe hunter2. Vous devez stocker quelque chose dans votre base de données pour que, lorsqu'il se connecte la semaine prochaine, vous puissiez vérifier qu'il a entré la bonne valeur.
La solution naïve est de stocker hunter2 directement. C'est catastrophique. Toute violation de base de données, toute injection SQL, tout backup laissé dans un bucket S3 mal configuré -- l'attaquant dispose maintenant du mot de passe réel de chaque utilisateur.
L'étape suivante est de le hacher. SHA-256("hunter2") vous donne une chaîne de longueur fixe que vous ne pouvez pas inverser. Stockez cela à la place. Mieux, non ?
Mieux -- mais pas suffisant.
Le problème est que SHA-256 est conçu pour être rapide. Les GPU modernes peuvent calculer des milliards de hachages SHA-256 par seconde. Un attaquant disposant d'une base de données de mots de passe hachés en SHA-256 et d'un bon GPU peut craquer une part significative des mots de passe courants en heures, parfois en minutes, en utilisant des tables précalculées (rainbow tables) ou des attaques par dictionnaire.
Bcrypt a été spécifiquement conçu pour résoudre ce problème. Il est intentionnellement lent, et la vitesse est configurable.
Vous pouvez expérimenter directement avec les hachages bcrypt grâce à notre Bcrypt Hash Generator -- aucune configuration requise.
Ce qu'est réellement Bcrypt
Bcrypt est une fonction de hachage de mots de passe conçue par Niels Provos et David Mazieres en 1999, basée sur le chiffrement Blowfish. Contrairement à SHA-256 ou MD5 (fonctions de hachage cryptographiques générales), bcrypt a été construit dès le départ spécifiquement pour le stockage des mots de passe.
Trois propriétés le rendent bien adapté :
1. Il est lent par conception
Bcrypt inclut un facteur de coût configurable (également appelé facteur de travail ou tours de sel). La fonction effectue 2^coût itérations en interne. Augmenter le facteur de coût de 1 double le temps de calcul. Cela signifie que vous pouvez ajuster la vitesse pour correspondre à votre matériel -- et à mesure que le matériel devient plus rapide, vous pouvez augmenter le facteur de coût pour rester en avance.
Un hachage SHA-256 prend des microsecondes. Un hachage bcrypt avec le coût 12 prend environ 200 à 300 millisecondes. Cette différence semble petite, mais elle change radicalement l'économie de l'attaquant.
2. Il gère automatiquement le salage
Un sel est une valeur aléatoire ajoutée au mot de passe avant le hachage. Le salage garantit que deux utilisateurs avec le même mot de passe obtiennent des hachages différents, et il empêche les attaques par rainbow tables précalculées.
Bcrypt génère automatiquement un sel aléatoire cryptographique de 128 bits et l'intègre dans le hachage de sortie. Vous n'avez pas besoin de gérer les sels vous-même.
3. Le hachage est autonome
La sortie de bcrypt contient la version de l'algorithme, le facteur de coût, le sel et le hachage -- le tout en une seule chaîne. Cela signifie que vous n'avez besoin de stocker qu'une seule chaîne par utilisateur, et vous pouvez vérifier un mot de passe sans récupérer le sel séparément.
Un hachage bcrypt typique ressemble à ceci :
$2b$12$LJ3m6gEwO/fSFqCVXWLwOeR/dYtTVkRDCwoGLBE0Fg6voFEOB5viy
Décomposition :
$2b$ -- version de l'algorithme (2b est la norme actuelle)
12$ -- facteur de coût (2^12 = 4 096 itérations du calendrier de clés)
LJ3m6gEwO/fSFqCVXWLwOe -- sel encodé en base64 sur 22 caractères (128 bits)
R/dYtTVkRDCwoGLBE0Fg6voFEOB5viy -- hachage encodé en base64 sur 31 caractères
Hachage vs. Chiffrement : La distinction clé
Cette distinction mérite d'être énoncée clairement.
Le hachage est une fonction unidirectionnelle. Vous entrez un mot de passe et obtenez un hachage. Il n'y a pas de clé, pas d'opération inverse. La seule façon de vérifier si un mot de passe correspond à un hachage est de hacher le mot de passe candidat et de comparer le résultat.
Le chiffrement est une fonction bidirectionnelle. Vous chiffrez des données avec une clé et pouvez les déchiffrer en original avec la même (ou une clé associée).
Les mots de passe doivent toujours être hachés, pas chiffrés. Si vous chiffrez les mots de passe, votre système contient quelque part une clé de déchiffrement, et quiconque obtient cette clé a tous les mots de passe de vos utilisateurs. Avec le hachage, une violation de base de données expose des hachages, pas des mots de passe -- et avec bcrypt, ces hachages sont longs à craquer.
Le facteur de coût : Choisir la bonne lenteur
Le facteur de coût contrôle directement le calcul effectué par bcrypt. Chaque incrément double le travail.
| Facteur de coût | Itérations | Temps approximatif (serveur typique) |
|---|---|---|
| 10 | 1 024 | ~65ms |
| 11 | 2 048 | ~130ms |
| 12 | 4 096 | ~250ms |
| 13 | 8 192 | ~500ms |
| 14 | 16 384 | ~1 000ms |
Les temps ci-dessus varient considérablement selon le matériel. Effectuez des benchmarks sur votre matériel de production réel avant de décider.
La recommandation actuelle de l'OWASP est un facteur de coût de 10 au minimum, ciblant un temps de hachage de 100 ms ou plus. La plupart des praticiens utilisent 12 comme valeur par défaut raisonnable aujourd'hui.
Le compromis :
- Trop bas (8 ou moins) : Les hachages sont assez rapides pour qu'un attaquant disposant d'un bon GPU puisse progresser rapidement contre une base de données compromise.
- Trop haut (15+) : Les demandes de connexion légitimes prennent plus d'une seconde chacune, ce qui est perceptible pour les utilisateurs et crée un potentiel de déni de service.
- Zone idéale (~12) : ~250 ms par hachage est assez lent pour entraver significativement les attaquants, assez rapide pour que les utilisateurs ne le remarquent pas.
Implémenter Bcrypt : Exemples de code
Node.js
import bcrypt from 'bcrypt';
const COST_FACTOR = 12;
// Hachage d'un mot de passe
async function hashPassword(plaintext) {
const hash = await bcrypt.hash(plaintext, COST_FACTOR);
return hash;
// "$2b$12$..." -- stocker cette chaîne dans votre base de données
}
// Vérification d'un mot de passe lors de la connexion
async function verifyPassword(plaintext, storedHash) {
const match = await bcrypt.compare(plaintext, storedHash);
return match; // true ou false
}
// Exemple d'utilisation
const hash = await hashPassword('hunter2');
console.log(hash); // $2b$12$...
const valid = await verifyPassword('hunter2', hash);
console.log(valid); // true
const invalid = await verifyPassword('wrongpassword', hash);
console.log(invalid); // false
Python (avec le paquet bcrypt)
import bcrypt
COST_FACTOR = 12
def hash_password(plaintext: str) -> str:
"""Hache un mot de passe et retourne la chaîne de hachage bcrypt."""
password_bytes = plaintext.encode('utf-8')
salt = bcrypt.gensalt(rounds=COST_FACTOR)
hashed = bcrypt.hashpw(password_bytes, salt)
return hashed.decode('utf-8')
def verify_password(plaintext: str, stored_hash: str) -> bool:
"""Vérifie un mot de passe en clair contre un hachage bcrypt stocké."""
password_bytes = plaintext.encode('utf-8')
hash_bytes = stored_hash.encode('utf-8')
return bcrypt.checkpw(password_bytes, hash_bytes)
# Utilisation
hash_value = hash_password('hunter2')
print(hash_value) # $2b$12$...
print(verify_password('hunter2', hash_value)) # True
print(verify_password('wrongpassword', hash_value)) # False
PHP
<?php
// Hachage d'un mot de passe
function hashPassword(string $plaintext): string {
return password_hash($plaintext, PASSWORD_BCRYPT, ['cost' => 12]);
}
// Vérification d'un mot de passe
function verifyPassword(string $plaintext, string $storedHash): bool {
return password_verify($plaintext, $storedHash);
}
// Utilisation
$hash = hashPassword('hunter2');
echo $hash; // $2y$12$...
var_dump(verifyPassword('hunter2', $hash)); // bool(true)
var_dump(verifyPassword('wrongpassword', $hash)); // bool(false)
?>
Erreurs courantes et comment les éviter
Stocker des mots de passe en clair ou avec un encodage réversible
Base64 est un encodage, pas un hachage. base64("hunter2") donne aHVudGVyMg==. Tout attaquant voyant cela peut le décoder en une ligne.
Utiliser des fonctions de hachage rapides pour les mots de passe
SHA-256, SHA-512, MD5, SHA-1 -- tous sont conçus pour être rapides. La rapidité est la mauvaise propriété pour le hachage de mots de passe.
Le problème de troncature à 72 octets
La spécification bcrypt originale ne traite que les 72 premiers octets de l'entrée. La solution standard est de hacher d'abord l'entrée avec SHA-256, puis de hacher ce résultat avec bcrypt :
import crypto from 'crypto';
import bcrypt from 'bcrypt';
async function hashLongPassword(plaintext) {
const prehashed = crypto
.createHash('sha256')
.update(plaintext)
.digest('base64');
return bcrypt.hash(prehashed, 12);
}
Tester les hachages Bcrypt
Notre Bcrypt Hash Generator est utile pour :
- Générer des hachages de test pendant le développement sans configurer un projet
- Vérifier que votre implémentation produit une sortie bcrypt valide
- Tester rapidement la vérification hachage-mot de passe dans votre code
L'outil fonctionne entièrement dans votre navigateur et n'envoie jamais de données à un serveur.
Bcrypt vs. les alternatives
| Algorithme | Intensif en mémoire | Résistant au GPU | Statut OWASP | Notes |
|---|---|---|---|---|
| Bcrypt | Non | Partiel | Recommandé | Éprouvé, limite 72 octets |
| Argon2id | Oui | Oui | Préféré | Vainqueur PHC, plus récent |
| scrypt | Oui | Oui | Acceptable | Intensif en mémoire, paramètres complexes |
| PBKDF2 | Non | Non | Acceptable | Approuvé NIST, conforme FIPS |
| SHA-256 (simple) | Non | Non | Ne pas utiliser | Pas un hachage de mot de passe |
Conclusion
Le hachage des mots de passe est l'un de ces domaines où la différence entre "fonctionne" et "fonctionne correctement" compte beaucoup. Bcrypt vous offre trois choses importantes : une lenteur intentionnelle, un salage automatique et un format de sortie autonome. Ce n'est pas la dernière option, mais elle est bien testée, universellement prise en charge et correcte.
Utilisez le facteur de coût 12 comme point de départ. Faites des benchmarks sur votre matériel réel. Augmentez-le si votre serveur peut hacher confortablement en moins de 200 ms. Et si vous partez de zéro, jetez un coup d'oeil à Argon2id.
Outils et ressources associés
- Bcrypt Hash Generator -- Générer et vérifier des hachages bcrypt dans le navigateur
- Password Generator -- Générer des mots de passe aléatoires forts
- Password Strength Checker -- Évaluer la force d'un mot de passe
- Hash Generator -- Générer des hachages MD5, SHA-1, SHA-256 et SHA-512
- Hash Functions Explained -- Analyse approfondie de SHA-256, MD5 et du hachage cryptographique