Comment bien utiliser les expressions régulières en C# pour valider les entrées utilisateur ?

Dans le développement d'applications, la validation des entrées utilisateur est cruciale pour garantir la sécurité et la fiabilité de l'application.

Comment bien utiliser les expressions régulières en C# pour valider les entrées utilisateur ?
Photo by Markus Spiske / Unsplash

Les expressions régulières sont un outil puissant pour valider les entrées utilisateur en C#. Elles peuvent être utilisées pour vérifier si une chaîne de caractères correspond à un certain format, comme une adresse email ou un numéro de téléphone.

Pour utiliser les expressions régulières en C#, vous devez d'abord inclure l'espace de nom System.Text.RegularExpressions. Ensuite, vous pouvez utiliser la classe Regex pour créer un objet expression régulière. Par exemple, voici comment créer une expression régulière pour valider les adresses email :

using System.Text.RegularExpressions;

// ...

string pattern = @"^[a-zA-Z0-9._%+-][email protected][a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$";
Regex emailRegex = new Regex(pattern);

La méthode statique IsMatch() de la classe Regex peut être utilisée pour vérifier si une chaîne de caractères correspond à l'expression régulière. Par exemple:

string email = "[email protected]";
if (emailRegex.IsMatch(email))
{
    // L'adresse email est valide
}
else
{
    // L'adresse email n'est pas valide
}

Il est important de noter que les expressions régulières peuvent être assez complexes, il est donc souvent utile de les tester avec des outils en ligne tels que https://regex101.com/ pour s'assurer qu'elles fonctionnent comme prévu.

Il est également possible de rechercher des correspondances dans une chaîne de caractères en utilisant la méthode Match() de la classe Regex, qui retourne un objet Match contenant les informations sur la première correspondance trouvée. Pour trouver toutes les correspondances, vous pouvez utiliser la méthode Matches(), qui retourne une collection d'objets Match .

Voici un exemple pour extraire tout les numéros de téléphones d'une chaine :

string input = "Voici mes numéros de téléphone : 06.00.00.00.00 et 0600000000";
string pattern = @"\d{2}.\d{2}.\d{2}.\d{2}.\d{2}|\d{10}";
Regex phoneRegex = new Regex(pattern);

MatchCollection matches = phoneRegex.Matches(input);
foreach (Match match in matches)
{
    Console.WriteLine(match.Value);
}

En résumé, les expressions régulières sont un outil puissant pour valider les entrées utilisateur en C#. En utilisant la classe Regex, vous pouvez créer des expressions régulières pour vérifier si une chaîne de caractères correspond à un certain format, comme une adresse email ou un numéro de téléphone. Vous pouvez utiliser les méthodes IsMatch(), Match(), et Matches() pour effectuer des vérifications et des recherches de correspondances. Il est important de tester vos expressions régulières avec des outils en ligne pour vous assurer qu'elles fonctionnent comme prévu.

Attention aux attaques ReDos

Les risques ReDos (Regular Expression Denial of Service) sont un type de vulnérabilité qui peut survenir lorsque les expressions régulières sont mal utilisées. Cela se produit lorsque les expressions régulières sont mal conçues et peuvent être utilisées pour faire planter une application ou un serveur en générant des calculs intensifs.

Une des principales causes des risques ReDos est l'utilisation de motifs répétitifs non bornés, tels que les boucles infinies ou les motifs répétitifs à l'intérieur de motifs répétitifs. Par exemple, voici une expression régulière qui est sujette à des risques ReDos :

a*a*a*a*a*a*a*

Cette expression régulière correspond à une chaîne qui contient zéro ou plusieurs caractères "a", ce qui signifie qu'elle peut correspondre à n'importe quelle chaîne, y compris des chaînes très longues. Si cette expression régulière est utilisée pour valider des entrées utilisateur, elle peut causer des calculs intensifs lorsqu'elle est utilisée avec une chaîne longue, entraînant ainsi un déni de service.

Pour éviter les risques ReDos, il est important de concevoir des expressions régulières qui sont efficaces pour la tâche spécifique à laquelle elles sont destinées. Il est également important de limiter la longueur des entrées utilisateur pour éviter les calculs intensifs. Voici quelques bonnes pratiques pour éviter les risques ReDos:

  • Utilisez les quantificateurs bornés, comme {n}, {n,} et {n,m} pour limiter la répétition des motifs.
  • Evitez les motifs à l'intérieur de motifs répétitifs.
  • Utilisez des motifs atomiques pour éviter les sous-correspondances imbriquées.
  • Utiliser des outils de test d'expression régulière pour vérifier que les expressions régulières ne sont pas sujettes à des risques ReDos.

Voici un exemple comment limiter la répétition des motifs

string pattern = @"^[a-zA-Z0-9._%+-]{1,255}@[a-zA-Z0-9.-]{1,255}\.[a-zA-Z]{2,}$";

cas concret

Imaginez une application web qui utilise une expression régulière pour valider les noms d'utilisateur lorsque les utilisateurs s'inscrivent. L'expression régulière utilisée est la suivante:

string pattern = @"^[a-zA-Z0-9]*$";
Regex usernameRegex = new Regex(pattern);

Cette expression régulière correspond à une chaîne qui ne contient que des caractères alphanumériques. Cependant, elle est sujette à une attaque ReDos car elle utilise un caractère générique * qui correspond à zéro ou plusieurs caractères, ce qui signifie qu'elle peut correspondre à n'importe quelle chaîne, y compris des chaînes très longues.

Un attaquant pourrait alors envoyer une requête HTTP avec un nom d'utilisateur très long, comme "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"

et faire "planter" le système. Cet exemple fictif montre comment une expression régulière mal conçue peut rendre une application vulnérable à une attaque ReDos. L'expression régulière utilisée pour valider les noms d'utilisateur "^[a-zA-Z0-9]*$" est sujette à une attaque ReDos car elle utilise un caractère générique * qui correspond à zéro ou plusieurs caractères, ce qui signifie qu'elle peut correspondre à n'importe quelle chaîne, y compris des chaînes très longues. Un attaquant pourrait alors envoyer une requête HTTP avec un nom d'utilisateur très long qui entraînerait des calculs intensifs pour l'application et causerait un déni de service. Il est donc important de concevoir des expressions régulières qui sont efficaces pour la tâche spécifique à laquelle elles sont destinées et de limiter la longueur des entrées utilisateur pour éviter les calculs intensifs et les attaques ReDos.

Eviter d'utiliser le caractère générique *

Il existe plusieurs façons d'éviter l'utilisation d'un caractère générique * dans les expressions régulières pour éviter les risques ReDos:

  1. Utilisez un quantificateur borné : Au lieu d'utiliser un * qui correspond à zéro ou plusieurs caractères, vous pouvez utiliser un quantificateur borné comme {n}, {n,} ou {n,m} pour spécifier le nombre exact de répétitions que vous souhaitez. Par exemple, pour limiter un nom d'utilisateur à 10 caractères alphanumériques, vous pouvez utiliser l'expression régulière suivante :
string pattern = @"^[a-zA-Z0-9]{1,10}$";

2. Utilisez des motifs atomiques : En utilisant les motifs atomiques, vous pouvez empêcher les sous-correspondances imbriquées qui peuvent causer des calculs intensifs. Par exemple, vous pouvez utiliser les parenthèses pour créer un motif atomique :

string pattern = @"^([a-zA-Z0-9]){1,10}$";

3. Utilisez des lookaheads et des lookbehinds pour limiter les correspondances : Les lookaheads et les lookbehinds peuvent être utilisés pour limiter les correspondances sans consommer de caractères. Par exemple, pour limiter un nom d'utilisateur à 10 caractères alphanumériques, vous pouvez utiliser l'expression régulière suivante :

string pattern = @"^(?=.{1,10}$)[a-zA-Z0-9]*$";

Utilisez des outils de test d'expression régulière pour vérifier que les expressions régulières ne sont pas sujettes à des risques ReDos.

Conclusion

En utilisant ces bonnes pratiques, vous pouvez éviter les risques ReDos dans vos applications C# et garantir un bon fonctionnement de votre code. Il est important de continuer à surveiller et à tester régulièrement les expressions régulières pour s'assurer qu'elles ne sont pas sujettes à des risques ReDos.

En résumé, les risques ReDos sont des vulnérabilités qui peuvent survenir lorsque les expressions régulières sont mal utilisées et peuvent causer des calculs intensifs. Pour éviter les risques ReDos, il est important de concevoir des expressions régulières qui sont efficaces pour la tâche spécifique à laquelle elles sont destinées, limiter la longueur des entrées utilisateur et utiliser des outils de test d'expression régulière pour vérifier que les expressions régulières ne sont pas sujettes à des risques ReDos.