Security
7 min read
9713 views

Le mot de passe de 1 Mo : faire planter les backends via l'épuisement du hashing 🏎️💥

IT
InstaTunnel Team
Published by our engineering team
Le mot de passe de 1 Mo : faire planter les backends via l'épuisement du hashing 🏎️💥

Dans le domaine de la cybersécurité, on nous apprend souvent que la lenteur est préférable. Lorsqu’il s’agit de hashing de mot de passe, nous choisissons délibérément des algorithmes comme Argon2id ou Bcrypt car ils sont “coûteux”. Ils sont conçus pour consommer des cycles CPU et de la mémoire afin de rendre économiquement impossible pour les hackers de réaliser des attaques par force brute.

Mais que se passe-t-il lorsque cet “investissement” se retourne contre vous ?

Entrez dans le 1MB Password Attack. C’est un vecteur de déni de service (DoS) silencieux, élégant et d’une simplicité dévastatrice. En envoyant une chaîne surdimensionnée — disons, 1 mégaoctet de caractères aléatoires — dans votre champ de connexion ou d’inscription, un attaquant peut forcer votre serveur à passer des secondes, voire des minutes, à hasher une seule requête.

Une dizaine de ces requêtes peut faire monter votre CPU à 100 %, désactivant efficacement tout votre backend. Dans cet article, nous analyserons la mécanique de l’épuisement du hashing, pourquoi les frameworks modernes vous rendent vulnérable, et comment y remédier sans compromettre la sécurité.

1. Le paradoxe du hashing “lent”

Pour comprendre cette vulnérabilité, il faut examiner comment fonctionnent les fonctions de hashing. Les algorithmes modernes comme Bcrypt, Scrypt et Argon2 sont “adaptatifs”. Ils utilisent un Work Factor (ou coût) pour déterminer le nombre d’itérations de la fonction de hashing.

$O(n)$ vs. Work Factor

La plupart des développeurs se concentrent sur le work factor. Si vous réglez Bcrypt sur un coût de 12, cela prend environ 250 ms pour hasher un mot de passe. Si vous passez à 13, cela prend 500 ms. Ce temps est constant, que le mot de passe soit “password123” ou “correct-horse-battery-staple”.

Cependant, il existe une variable cachée : la longueur de l’entrée ($n$).

Alors que le work factor offre une protection exponentielle contre la force brute, la fonction de hashing doit encore traiter chaque octet de la chaîne d’entrée. La complexité est approximativement $O(n \times \text{work factor})$.

Quand $n$ est de 15 caractères, l’impact est négligeable. Quand $n$ atteint 1 000 000 de caractères (1 Mo), le CPU doit calculer le hash sur une quantité massive de données tout en exécutant des milliers d’itérations.

Pourquoi c’est un “tueur silencieux”

La plupart des attaques DoS sont volumétriques (inondation du réseau) ou basées sur des protocoles (SYN floods). Les pare-feux et WAF (Web Application Firewalls) sont efficaces pour bloquer ces attaques. Mais une requête POST de 1 Mo ressemble à une donnée utilisateur parfaitement valide (même si un peu volumineuse). Comme elle cible la couche applicative, elle contourne de nombreuses défenses réseau traditionnelles.

2. Anatomie de l’attaque : la charge utile de 1 Mo

Imaginez un point d’entrée de connexion standard : POST /api/v1/login.

Une requête typique pourrait ressembler à ceci :

{
  "username": "victim@example.com",
  "password": "pA$$w0rd123!"
}

Maintenant, imaginez que l’attaquant envoie ceci :

{
  "username": "victim@example.com",
  "password": "a...[999 990 'a']...a"
}

La montée en charge du CPU

Lorsque votre serveur reçoit cela, il passe cette chaîne de 1 Mo à la bibliothèque de hashing.

  • L’impact mémoire : le serveur doit allouer au moins 1 Mo de RAM juste pour contenir la chaîne dans le corps de la requête.
  • L’impact hashing : le CPU commence à tourner à plein régime. Pour Argon2id, qui est mémoire-intensive, il pourrait essayer d’allouer 64 Mo de RAM par hash et exécuter 3 itérations sur cette entrée de 1 Mo.
  • Le blocage du thread : dans de nombreux environnements (comme Node.js ou Python/Django), le hashing s’effectue sur le thread principal ou un pool limité de workers. Pendant que le CPU hash cette chaîne de 1 Mo, il ne peut pas traiter d’autres requêtes.

3. Comparaison des vulnérabilités : Bcrypt vs. Argon2 vs. PBKDF2

Tous les algorithmes de hashing ne gèrent pas la longueur des chaînes de la même façon. Ironiquement, certains “anciens” défauts offrent en réalité une couche de protection.

Bcrypt : le “bouclier” de 72 octets

Bcrypt a une particularité célèbre : il ne considère que les 72 premiers octets d’un mot de passe. Les caractères après le 72ème sont ignorés.

  • Le point faible : les utilisateurs avec des mots de passe de 100 caractères ne sont pas aussi sécurisés qu’ils le pensent.
  • L’avantage DoS : comme il tronque l’entrée presque immédiatement, envoyer un mot de passe de 1 Mo à une fonction Bcrypt ne provoque généralement pas de pic CPU. La bibliothèque regarde les 72 premiers octets et ignore le reste.

Argon2id : la vulnérabilité moderne

Argon2id (le standard actuel en 2026) a été conçu pour corriger les limitations de Bcrypt. Il gère des entrées de longueur arbitraire. Si cela renforce la sécurité et les passphrases, cela signifie aussi qu’il essaiera de hasher tout le 1 Mo que vous lui envoyez. Sans limite au niveau de l’application, Argon2 devient une cible privilégiée pour les attaques d’épuisement.

PBKDF2 : le cauchemar des itérations

PBKDF2 est souvent utilisé avec SHA-256. Bien qu’il n’ait pas de limite de 72 octets, il est purement CPU-bound. Si un attaquant envoie une chaîne massive, la charge CPU augmente linéairement avec la longueur. Dans des frameworks comme Django (qui utilise PBKDF2 par défaut), cela peut entraîner une latence importante, même si le serveur ne plante pas immédiatement.

4. Pourquoi les frameworks manquent souvent cette vulnérabilité

En 2025 et 2026, de nombreux frameworks ont évolué vers des réglages “sécurisés par défaut”, mais ils se concentrent sur la longueur minimale, pas maximale.

  • Django : possède MinimumLengthValidator (par défaut 8 caractères). Il ne dispose pas d’un MaximumLengthValidator activé par défaut pour les mots de passe.
  • Laravel : valide min:8, mais rarement max:128.
  • Node.js (librairies Bcrypt/Argon2) : la plupart acceptent simplement une chaîne ou un Buffer. Si l’application passe le corps brut dans la fonction, la librairie tentera de le traiter.

La philosophie a toujours été : “Pourquoi empêcher un utilisateur d’avoir un mot de passe plus long et plus sécurisé ?” On a oublié qu’un “mot de passe” de 1 Mo n’est pas un mot de passe — c’est une grenade.

5. Mitigations stratégiques : protéger votre backend

Se défendre contre l’épuisement du hashing nécessite une approche en plusieurs couches. Il faut arrêter la “grenade” aussi loin que possible de votre CPU.

Mitigation 1 : La règle d’or (limites de longueur maximale)

La défense la plus simple et efficace est de fixer une limite stricte à la longueur du mot de passe.

Recommandation : fixer une longueur maximale de 128 ou 256 caractères.

Même le plus extrême des experts en sécurité n’a pas besoin d’un mot de passe de plus de 256 caractères. C’est suffisamment long pour toute phrase secrète raisonnable, tout en étant court pour que le hashing reste trivial pour le serveur.

Exemple (Django):

# settings.py
AUTH_PASSWORD_VALIDATORS = [
    {
        'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
        'OPTIONS': {'min_length': 12},
    },
    # Ajoutez un MaxLengthValidator personnalisé ou intégré si disponible
]

Mitigation 2 : La technique du “Pre-Hash” SHA-256

Si vous devez absolument autoriser des mots de passe de longueur infinie (pour une raison cryptographique niche), utilisez un Pre-Hash.

Avant de passer le mot de passe à Bcrypt ou Argon2, le hacher rapidement avec une fonction non adaptative comme SHA-256.

  1. L’utilisateur envoie un mot de passe de 1 Mo.
  2. Le serveur calcule temp_hash = SHA-256(mot_de_passe).
  3. La sortie de SHA-256 est toujours une chaîne fixe de 32 octets.
  4. Le serveur calcule final_hash = Bcrypt(temp_hash).

Cela garantit que l’algorithme “coûteux” (Bcrypt/Argon2) ne voit qu’une petite entrée de taille fixe.

Note : Si vous implémentez cela, soyez cohérent. Vous ne pouvez pas passer à un pré-hachage pour les utilisateurs existants sans plan de migration, car les hashes ne correspondront plus.

Mitigation 3 : Limitation du débit par IP et nom d’utilisateur

Les attaques d’épuisement reposent sur le volume. Même si un mot de passe de 1 Mo prend 2 secondes à hasher, une seule requête ne tue pas un serveur. Dix requêtes simultanées, oui.

  • Implémentez une limitation stricte du débit sur les endpoints de connexion et d’inscription.
  • Utilisez un algorithme de “leaky bucket” pour ralentir les tentatives répétées depuis la même IP.

Mitigation 4 : WAF et limites de payload

Configurez votre Load Balancer (Nginx, AWS ALB) ou WAF (Cloudflare, Akamai) pour rejeter les payloads suspectement volumineux.

Si votre formulaire de connexion ne comporte que le nom d’utilisateur et le mot de passe, le corps POST entier ne devrait pas dépasser 10 Ko. Rejetez tout ce qui est plus grand à la périphérie.

6. Exemples concrets d’implémentation

Node.js (Express + Joi)

Utiliser une bibliothèque de validation comme Joi facilite l’application de ces limites avant que les données n’atteignent votre logique de hashing.

const loginSchema = Joi.object({
  username: Joi.string().email().required(),
  password: Joi.string().min(12).max(128).required() // La ligne critique
});

app.post('/login', (req, res) => {
  const { error } = loginSchema.validate(req.body);
  if (error) return res.status(400).send(error.details[0].message);
  
  // Ce n'est qu'à ce moment que l'on appelle le hash coûteux
  const isValid = await bcrypt.compare(req.body.password, user.hash);
});

PHP (Laravel)

Le moteur de validation de Laravel simplifie cela en une ligne.

$request->validate([
    'email' => 'required|email',
    'password' => 'required|string|min:12|max:255', // Fixe la limite
]);

7. Tableau comparatif : Algorithmes de hashing et vulnérabilité DoS

Algorithme Limite max par défaut Vulnérabilité DoS (sans limite) Recommandation 2026
Bcrypt 72 octets Faible (troncature) Idéal pour legacy / RAM limitée
Argon2id Aucune Élevée Optimal avec limite de 128 caractères
Scrypt Aucune Moyenne/Élevée Bon, mais Argon2id préféré
PBKDF2 Aucune Moyenne À utiliser seulement si Argon2 indisponible

Conclusion : La disponibilité comme une caractéristique de sécurité

On a tendance à considérer Sécurité et Disponibilité comme deux silos séparés. On durcit nos hashes pour éviter les violations de données (Sécurité), mais on oublie qu’un serveur non réactif, c’est un serveur défaillant (Disponibilité).

Le “mot de passe de 1 Mo” rappelle que chaque octet d’entrée utilisateur a un coût. En ajoutant simplement une contrainte max_length: 128, vous fermez une énorme faille DoS tout en maintenant les plus hauts standards de cryptographie.

Ne laissez pas votre “sécurité forte” devenir la cause de votre chute.

Continue from this article into the most relevant product guides and workflows.

Related Topics

#hashing exhaustion attack, oversized password dos, 1mb password attack, authentication denial of service, bcrypt dos vulnerability, argon2 dos attack, password hashing abuse, cpu exhaustion attack, authentication bypass via dos, login endpoint attack, hashing performance vulnerability, resource exhaustion vulnerability, password field length limit, secure authentication failure, backend dos via hashing, computational denial of service, cryptographic dos attack, application layer dos, slow hashing attack, password abuse attack, authentication system crash, brute force mitigation bypass, login dos vulnerability, web application dos, form field abuse, cpu spike attack, denial of wallet via hashing, authentication performance attack, heavy computation vulnerability, server resource exhaustion, password validation vulnerability, api authentication dos, web security flaw, login endpoint overload, cloud resource exhaustion, cost amplification attack, cryptographic workload attack, password handling vulnerability, secure coding mistakes, input validation failure, application level attack vector, backend performance exploit, security misconfiguration, denial of service technique, web app resilience, auth system hardening, rate limiting bypass, cpu pinning attack, hash algorithm abuse, argon2 security pitfalls, bcrypt performance issues, password hashing attack vector, authentication threat model, login security risks, resource based attacks, web application security 2025, denial of wallet attacks, cloud billing abuse, backend crash vulnerability, defensive coding practices, auth endpoint protection, password length enforcement, hashing attack mitigation, secure authentication design

Keep building with InstaTunnel

Read the docs for implementation details or compare plans before you ship.

Share this article

More InstaTunnel Insights

Discover more tutorials, tips, and updates to help you build better with localhost tunneling.

Browse All Articles