Index
Déni de service par expression régulière
Description
Le déni de service par expression régulière (ReDoS) est une vulnérabilité de sécurité qui se produit lorsque l'entrée de l'utilisateur est utilisée pour construire une expression régulière. En présence d'un motif d'expression régulière soigneusement conçu, l'application peut dépenser une quantité substantielle de ressources, ce qui peut entraîner un déni de service.
Voici quelques exemples de motifs malveillants :
(a+)+([a-zA-Z]+)*(a|aa)+(a|a?)+(.*a){x} for x > 10
Et les exemples de code suivants illustrent des implémentations incorrectes :
```java import java.util.regex.*;
public class RegexVulnerabilityExample { public static void main(String[] args) { // Function to read user input, potentially malicious String userInput = getUserInput();
// Constructing a regular expression using user input
Pattern pattern = Pattern.compile(userInput);
// Using the regular expression
Matcher matcher = pattern.matcher("input_string");
boolean matchFound = matcher.find();
if (matchFound) {
System.out.println("Match found!");
} else {
System.out.println("No match found!");
}
} ```
```swift import Foundation
func checkRegex(input: String, regex: String) {
// Constructing a regular expression using user input
do {
let regex = try NSRegularExpression(pattern: userInput)
let range = NSRange(location: 0, length: input.utf16.count)
let matchRange = regex.rangeOfFirstMatch(in: input, options: [], range: range)
if matchRange.location != NSNotFound {
print("Match found!")
} else {
print("No match found!")
}
} catch {
print("Error: Invalid regular expression")
}
}
// Call the function with user input checkRegex(input: "input_string",regex: "redos") ```
```dart import 'package:flutter/material.dart'; import 'package:flutter/services.dart';
void main() { runApp(MyApp()); }
class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( home: Scaffold( appBar: AppBar( title: Text('Regex Vulnerability Example'), ), body: Center( child: ElevatedButton( onPressed: () { // Function to read user input, potentially malicious String userInput = getUserInput();
// Constructing a regular expression using user input
RegExp regex = RegExp(userInput);
// Using the regular expression
String inputString = "input_string";
bool matchFound = regex.hasMatch(inputString);
if (matchFound) {
print("Match found!");
} else {
print("No match found!");
}
},
child: Text('Test Regex'),
),
),
),
);
} ```
Recommandation
Pour atténuer les vulnérabilités de déni de service par expression régulière (ReDoS), prenez en compte les recommandations suivantes :
-
Minimiser la dépendance aux entrées utilisateur : Chaque fois que possible, minimisez le recours aux entrées fournies par l'utilisateur pour construire des expressions régulières (regex). Envisagez des approches alternatives ou des modèles de conception qui réduisent le besoin de générer dynamiquement des regex en fonction des entrées de l'utilisateur. En limitant l'exposition à des modèles potentiellement malveillants, vous pouvez réduire considérablement le risque de vulnérabilités ReDoS.
-
Valider les entrées utilisateur : Mettez en œuvre des mécanismes de validation robustes pour vous assurer que les entrées fournies par les utilisateurs pour la construction de regex respectent des critères prédéfinis. Validez la longueur, la complexité et la structure des modèles d'entrée pour atténuer le risque d'expressions créées de manière malveillante. En validant les entrées dès le départ, vous pouvez identifier et rejeter de manière préventive les modèles potentiellement dangereux.
-
Mettre en œuvre des mécanismes de limitation de débit et de délai d'attente : Appliquez des mécanismes de limitation de débit et de délai d'attente (timeout) pour restreindre le temps d'exécution et la consommation de ressources associés à l'évaluation des regex. Fixez des limites appropriées sur la complexité et la durée des opérations de correspondance regex afin d'éviter une surcharge de calcul excessive. En imposant des contraintes raisonnables sur le traitement des regex, vous pouvez atténuer le risque d'attaques ReDoS et assurer la stabilité de votre application dans diverses conditions d'entrée.
```java import java.util.Scanner; import java.util.concurrent.*;
public class TimeoutDatabaseCheckExample { public static void main(String[] args) { // Create a Scanner object to read user input Scanner scanner = new Scanner(System.in);
// Prompt the user to enter a regex pattern
System.out.print("Enter a regex pattern: ");
String regexPattern = scanner.nextLine();
// Set the timeout duration in milliseconds
long timeoutDuration = 1000; // 1 second
// Create an ExecutorService with a single thread
ExecutorService executor = Executors.newSingleThreadExecutor();
// Submit the database check task to the executor
Future<Boolean> future = executor.submit(() -> {
// Perform the database check operation
return checkDatabase(regexPattern);
});
try {
// Wait for the result with timeout
boolean recordExists = future.get(timeoutDuration, TimeUnit.MILLISECONDS);
// Check if the record exists in the database
if (recordExists) {
System.out.println("Record exists in the database!");
} else {
System.out.println("Record not found in the database.");
}
} catch (TimeoutException e) {
// Handle timeout
System.out.println("Database operation timed out.");
} catch (InterruptedException | ExecutionException e) {
// Handle other exceptions
e.printStackTrace();
} finally {
// Shutdown the executor
executor.shutdown();
}
// Close the scanner
scanner.close();
}
// Hypothetical database check function
public static boolean checkDatabase(String regexPattern) {
// Perform the database check operation here
// For demonstration purposes, assume the record exists if the regex pattern matches
return Pattern.compile(regexPattern).matcher("record_from_database").find();
}
}
```
```swift import Foundation
// Function to perform database check func checkDatabase(forRegexPattern regexPattern: String) -> Bool { // Perform the database check operation here // For demonstration purposes, assume the record exists if the regex pattern matches let inputString = "record_from_database" return inputString.range(of: regexPattern, options: .regularExpression) != nil }
// Function to perform database check with timeout func checkDatabaseWithTimeout(forRegexPattern regexPattern: String, timeout: TimeInterval) -> Bool? { var result: Bool?
// Create a dispatch group
let group = DispatchGroup()
// Create a dispatch queue
let queue = DispatchQueue.global()
// Enter the dispatch group
group.enter()
// Asynchronously perform the database check operation
queue.async {
result = checkDatabase(forRegexPattern: regexPattern)
// Leave the dispatch group when the operation is complete
group.leave()
}
// Wait for the operation to complete with timeout
let dispatchResult = group.wait(timeout: .now() + timeout)
// Check if the operation timed out
if dispatchResult == .timedOut {
// Return nil indicating timeout
return nil
}
// Return the result of the database check operation
return result
}
// Function to get regex pattern from user input func getRegexPatternFromUser() -> String { print("Enter the regex pattern:") guard let input = readLine() else { return "" } return input }
// Example usage let regexPattern = getRegexPatternFromUser() let timeoutDuration = 1.0 // Timeout duration in seconds
if !regexPattern.isEmpty { if let recordExists = checkDatabaseWithTimeout(forRegexPattern: regexPattern, timeout: timeoutDuration) { if recordExists { print("Record exists in the database!") } else { print("Record not found in the database.") } } else { print("Database operation timed out.") } } else { print("Invalid regex pattern.") }
```
Liens
- OWASP : Regular expression Denial of Service - ReDoS
- CWE-1333: Inefficient Regular Expression Complexity
Normes
- PCI_STANDARDS:
- REQ_6_2
- REQ_6_4
- OWASP_MASVS_L1:
- MSTG_PLATFORM_2
- OWASP_MASVS_L2:
- MSTG_PLATFORM_2
- OWASP_MASVS_v2_1:
- MASVS_CODE_4
- SOC2_CONTROLS:
- CC_2_1
- CC_4_1
- CC_7_1
- CC_7_2
- CC_7_4
- CC_7_5
- CC_9_1
- HIPAA_CONTROLS:
- SECURITY212
- SECURITY213
- SECURITY255