Comment valider les expressions régulières en sécurité
Découvrez le backtracking catastrophique et les attaques ReDoS. Apprenez à valider les expressions régulières en toute sécurité avec des patrons fiables.

Dans le développement de logiciels modernes, savoir valider les expressions régulières (communément appelées regex) en toute sécurité est devenu un impératif majeur pour garantir la stabilité des infrastructures. Les expressions régulières sont des outils indispensables pour la recherche et la manipulation de motifs textuels. Toutefois, si elles sont mal conçues, elles peuvent rapidement exposer vos applications à de graves failles de sécurité.
Un modèle regex mal structuré offre aux attaquants l'opportunité de déclencher des attaques par déni de service (DoS) via l'épuisement des ressources processeur du serveur. Ce type de vulnérabilité est connu sous le nom de ReDoS (Regular Expression Denial of Service) et s'explique par un phénomène algorithmique appelé le backtracking catastrophique. Dans ce guide technique, nous examinerons le fonctionnement de ces vulnérabilités, comment les repérer dans votre code et comment tester et concevoir vos modèles en toute sécurité.
Qu'est-ce qu'une expression régulière et en quoi est-elle peu sûre ?
Une expression régulière est une suite de caractères définissant un motif de recherche textuel. On les utilise couramment pour valider des formats (adresses e-mail, numéros de téléphone, codes postaux) ou pour extraire des segments d'informations au sein de gros volumes de données.
La faille de sécurité liée aux expressions régulières ne provient pas d'un défaut classique de dépassement de tampon (buffer overflow) ou d'une injection de code, mais plutôt de la complexité algorithmique du moteur d'évaluation. La majorité des moteurs regex implémentés dans les langages courants comme JavaScript, Python, PHP, Ruby et .NET s'appuient sur un algorithme d'évaluation basé sur les automates finis non déterministes (NFA).
Un moteur NFA est extrêmement flexible et prend en charge des fonctionnalités avancées comme les références arrières (backreferences) et les assertions de survol (lookarounds). Mais cette flexibilité a un coût : devant des modèles ambigus ou des chaînes d'entrée complexes, le moteur doit explorer plusieurs chemins de recherche de manière récursive. Si le nombre de chemins à explorer croît de façon exponentielle par rapport à la taille de la chaîne d'entrée, le serveur finit par se bloquer.
Le danger du backtracking catastrophique et des attaques ReDoS
Le backtracking catastrophique se produit lorsque le moteur regex analyse une chaîne de caractères qui ne correspond pas au motif recherché, mais qui présente une forte similitude initiale. Pour valider une correspondance, le moteur avance caractère par caractère. S'il rencontre une discordance en cours de route, il revient en arrière (backtracks) vers un état précédent pour explorer un autre chemin d'évaluation.
Lorsque l'expression régulière intègre des quantificateurs imbriqués (par exemple, *, + ou {n,} placés à l'intérieur d'autres groupes répétitifs), le nombre de chemins de rechange à analyser se multiplie de manière exponentielle, et non linéaire.
Un attaquant malveillant peut tirer parti de ce comportement en soumettant une chaîne relativement courte (de 30 à 50 caractères) conçue pour échouer précisément au tout dernier caractère. Cela force le moteur NFA à effectuer des milliards de permutations de backtracking avant de pouvoir confirmer qu'il n'y a pas de correspondance. Cette opération monopolise le thread d'exécution du serveur, poussant l'utilisation du processeur à 100 % et coupant l'accès au service pour les autres utilisateurs.
Le rôle des assertions Lookaround dans la sécurité des regex
Les assertions lookaround (lookahead et lookbehind) sont des vérifications de largeur nulle qui permettent de valider un motif selon ce qui le précède ou le suit, sans inclure ces caractères dans le résultat final. Bien qu'elles s'avèrent utiles pour vérifier des critères de mots de passe complexes, elles peuvent s'avérer dangereuses si elles contiennent des quantificateurs de longueur variable.
Prenons le modèle suivant :
(?=\w+)\d+
Lorsqu'une assertion lookaround contient des quantificateurs variables (+, *, {n,}), le moteur doit inspecter la suite de la chaîne plusieurs fois. Si le processus global échoue et recule, il réévaluera le lookaround interne de façon répétée à chaque index de la chaîne. Cette imbrication accroît la classe de complexité de l'automate et multiplie les risques de latence extrême.
Exemple pratique de Backtracking Catastrophique
Pour illustrer le comportement d'une expression régulière vulnérable, étudions le motif suivant conçu pour valider une suite de lettres suivie d'un caractère spécial :
^(a+)+$
Ce modèle semble inoffensif : il recherche un ou plusieurs caractères a, répétés une ou plusieurs fois, du début (^) à la fin ($) de la chaîne. Néanmoins, l'imbrication des quantificateurs + fait grimper le nombre de regroupements possibles de façon exponentielle.
Si nous testons la chaîne aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa (30 caractères a), le moteur trouve immédiatement une correspondance en quelques microsecondes. Mais que se passe-t-il si un attaquant envoie la chaîne aaaaaaaaaaaaaaaaaaaaaaaaaaaaaab (30 a suivis d'un b) ?
Le moteur tente de valider les a mais échoue sur le b. Au lieu de s'arrêter, il effectue un backtracking et passe en revue toutes les manières possibles de structurer les a précédents afin de s'assurer qu'aucune combinaison ne permet de valider le motif complet.
// Simulation d'une regex vulnérable en Node.js
function testerRegexVulnerable() {
const motifVulnerable = /^(a+)+$/;
const entreeMalicieuse = "a".repeat(30) + "b"; // 30 lettres 'a' et un 'b'
console.log("Début de l'évaluation de la chaîne...");
const debut = performance.now();
// Cette instruction peut bloquer le thread Node.js pendant plusieurs secondes
const resultat = motifVulnerable.test(entreeMalicieuse);
const fin = performance.now();
console.log(`Évaluation terminée. Correspondance ?: ${result}`);
console.log(`Temps écoulé : ${(fin - debut).toFixed(2)} ms`);
}
testerRegexVulnerable();
Avec seulement 30 caractères, ce script peut bloquer le serveur pendant plusieurs secondes. Avec 40 caractères, le temps de calcul se compte en heures ou en jours de traitement continu à 100 % de la CPU.
Stratégies pour coder des expressions régulières sûres
Éviter les attaques ReDoS et s'assurer que vos validations sont fiables demande d'adopter des règles de programmation défensive :
1. Bannir l'ambiguïté et les répétitions redondantes
Veillez à ce que vos modèles ne contiennent pas de chemins d'évaluation superposés. Par exemple, au lieu d'utiliser (\w+)* ou (\s|\s+)*, préférez des formulations linéaires et restrictives.
2. Configurer des délais d'expiration (Timeouts)
Si vous exécutez des expressions régulières sur des serveurs de production (en particulier sur des environnements asynchrones comme Node.js), définissez un timeout. Si le moteur met plus de 50 ou 100 millisecondes à valider une entrée, interrompez l'opération immédiatement.
3. Privilégier les moteurs linéaires (DFA)
Dans la mesure du possible, utilisez des bibliothèques basées sur des automates finis déterministes (DFA) ou des algorithmes de recherche linéaires comme RE2 de Google. RE2 garantit un temps d'exécution proportionnel à la longueur de la chaîne ($O(n)$) en écartant les fonctions de backtracking problématiques.
Tableau comparatif de modèles vulnérables et sécurisés
| Cas d'utilisation | Modèle vulnérable (ReDoS) | Alternative sécurisée | Explication du changement |
|---|---|---|---|
| Validation de texte simple | ^(\w+)*$ |
^\w*$ |
Supprime le quantificateur imbriqué redondant. |
| Liste séparée por des virgules | ^([^,]+,)*[^,]+$ |
^[^,]+(,[^,]+)*$ |
Structure le motif sans créer de groupes superposés. |
| Espaces facultatifs | \s*\d+\s* |
\s\d+\s (ou limité avec {1}) |
Évite la récursion indéfinie sur les espaces. |
L'adoption de ces bonnes pratiques au sein de votre cycle de développement évitera les goulets d'étranglement de performance. Vous pouvez en apprendre plus sur le développement d'applications robustes dans notre article sur le développement web sécurisé et les protections OWASP ou découvrir comment inspecter votre code à l'aide d'analyses statiques et dynamiques dans notre guide d'une auditorie de code SAST et DAST.
Outil recommandé : Testeur de Regex de TecnoCrypter
Pour valider que vos expressions régulières ne présentent pas de risques de baisse de performance ou de backtracking avant de les déployer sur vos serveurs de production, nous vous conseillons d'utiliser notre Testeur de Regex de TecnoCrypter.
Cette application interactive vous permet de saisir vos modèles, de les confronter à différentes chaînes de test et de surveiller en temps réel les performances de traitement du moteur. En simulant des charges d'évaluation et en analysant la structure syntaxique de vos modèles, le testeur vous aide à prévenir les boucles infinies et à optimiser vos expressions régulières pour un rendement maximal et une sécurité optimale.
Conclusion
La validation des expressions régulières est une tâche courante de la programmation, mais elle ne doit pas être négligée. Un motif mal conçu peut ouvrir la voie à des attaques ReDoS catastrophiques. En structurant des modèles plus simples, en définissant des limites de temps de traitement, en adoptant des moteurs linéaires comme RE2 et en testant vos motifs en amont, vous renforcerez durablement la sécurité et la réactivité de vos serveurs.
Sécurisez vos serveurs dès aujourd'hui. Analysez la performance et la fiabilité de vos motifs sur notre Testeur de Regex de manière gratuite et interactive.
Sources et lectures recommandées :
- OWASP Foundation — Fiche d'information sur les attaques Regular Expression Denial of Service (ReDoS).
- CWE-1333 — Fiche de vulnérabilité : Inefficient Regular Expression Complexity.
- Google RE2 Repository — Moteur de recherche d'expressions régulières linéaire et sécurisé.
- Article connexe sur TecnoCrypter : Anatomie de l'injection SQL et méthodes de mitigation


