Permissiver Regulärer Ausdruck

Beschreibung

Permissiver Regulärer Ausdruck tritt auf, wenn ein Regex-Muster, das für Eingabevalidierung gedacht ist, zu nachsichtig ist und Eingaben durchlässt, die abgelehnt werden sollten. Häufige Probleme umfassen Verankerungsprobleme (keine Verwendung von ^ und $), gierige Quantifizierer, die zu viel matchen, Zeichenklassen-Fehler und Nichtberücksichtigung von Sonderzeichen oder Kodierungen. Der Regex scheint zu validieren, lässt aber tatsächlich bösartige Eingaben durch.

Risiko

Eingabevalidierungs-Bypasses ermöglichen Injection-Angriffe (SQL, XSS, Command). Fehlerhaft formatierte Daten gelangen ins System und verursachen Fehler oder unerwartetes Verhalten. Sicherheitsfilter, die auf Regex angewiesen sind, können umgangen werden. Datenintegritätsprobleme entstehen durch unsachgemäß validierte Eingaben. Authentifizierung kann umgangen werden, wenn Benutzername-/Passwort-Validierung zu permissiv ist.

Lösung

Verwenden Sie Anker (^ und $), um die gesamte Zeichenkette zu matchen. Testen Sie Regex gegen bekannt-schlechte Eingaben. Verwenden Sie nicht-gierige Quantifizierer, wo angemessen. Erwägen Sie die Verwendung dedizierter Validatoren anstelle von benutzerdefinierten Regex. Testen Sie Randfälle einschließlich leerer Strings, Sonderzeichen und verschiedener Kodierungen. Überprüfen Sie Regex auf häufige Fehler. Verwenden Sie Regex-Testtools, um Verhalten zu verifizieren.

Häufige Auswirkungen

AuswirkungDetails
SicherheitBereich: Validierungs-Bypass

Bösartige Eingaben passieren Validierungsprüfungen.
IntegritätBereich: Datenkorruption

Ungültige Daten gelangen ins System.
AuthentifizierungBereich: Bypass

Ungültige Credentials können akzeptiert werden.

Beispielcode + Lösungscode

Verwundbarer Code

// VERWUNDBAR: Fehlende Anker
function validateEmailVulnerable(email) {
    // Fehlende ^ und $ - matcht Teilstring
    return /\w+@\w+\.\w+/.test(email);
}

// Passiert Validierung:
validateEmailVulnerable("evil<script>@test.com");  // true! (matcht Teilstring)
validateEmailVulnerable("[email protected]<script>"); // true!

// VERWUNDBAR: Übermäßig permissive Zeichenklasse
function validateUsernameVulnerable(username) {
    // Erlaubt zu viele Zeichen
    return /^.{3,20}$/.test(username);
}

// Passiert:
validateUsernameVulnerable("admin'--");  // SQL-Injection-Zeichen passieren
validateUsernameVulnerable("<script>");  // XSS-Zeichen passieren

// VERWUNDBAR: Falsche Zeichenklasse
function validatePhoneVulnerable(phone) {
    // [0-9] beabsichtigt aber falsche Syntax
    return /^[0-9-]+$/.test(phone);
}

// Das - erstellt einen Bereich, passiert unerwartetes:
validatePhoneVulnerable("---");  // true
validatePhoneVulnerable("9-0");  // true

// VERWUNDBAR: Gierige Quantifizierer-Probleme
function extractURLVulnerable(text) {
    // .* ist gierig, matcht zu viel
    const match = text.match(/href="(.*)"/);
    return match ? match[1] : null;
}

// Gegeben: href="http://good.com" onclick="evil()"
// Gibt zurück: http://good.com" onclick="evil()
// Weil .* gierig bis zum letzten " matcht

// VERWUNDBAR: Groß-/Kleinschreibung
function validateCommandVulnerable(cmd) {
    // Fehlender case-insensitive Flag
    return /^(GET|POST|PUT|DELETE)$/.test(cmd);
}

// Passiert unerwartetes:
validateCommandVulnerable("get");   // false - aber sollte vielleicht gültig sein
validateCommandVulnerable("Get");   // false

// VERWUNDBAR: Unicode-/Kodierungs-Probleme
function validateNameVulnerable(name) {
    // \w matcht keine Unicode-Buchstaben
    return /^\w+$/.test(name);
}

// Lehnt gültige Namen ab:
validateNameVulnerable("José");    // false
validateNameVulnerable("北京");    // false
# VERWUNDBAR: Teilweises Matching
import re

def validate_ip_vulnerable(ip):
    # Fehlende ^ und $ - teilweises Match
    pattern = r'\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}'
    return re.search(pattern, ip) is not None

# Passiert:
validate_ip_vulnerable("evil192.168.1.1evil")  # True!
validate_ip_vulnerable("999.999.999.999")       # True (ungültige IP)

# VERWUNDBAR: Escape-Sequenz-Probleme
def validate_path_vulnerable(path):
    # Punkt nicht escaped - matcht jedes Zeichen
    pattern = r'^/var/www/.+.html

```java
// VERWUNDBAR: Musterkompilierungs-Probleme
public class VulnerableValidator {

    // Fehlendes CASE_INSENSITIVE könnte beabsichtigt sein, aber oft nicht
    private static final Pattern EMAIL_PATTERN =
        Pattern.compile("\\w+@\\w+\\.\\w+");  // Keine Anker!

    public boolean validateEmail(String email) {
        return EMAIL_PATTERN.matcher(email).find();  // find() nicht matches()!
    }

    // VERWUNDBAR: DOTALL-Modus-Probleme
    private static final Pattern SCRIPT_PATTERN =
        Pattern.compile("<script>.*</script>", Pattern.DOTALL);

    public String removeScripts(String html) {
        // Gieriges .* mit DOTALL entfernt zu viel
        return SCRIPT_PATTERN.matcher(html).replaceAll("");
    }
}

Lösungscode

// SICHER: Ordentliche Anker und Zeichenklassen
function validateEmailSafe(email) {
    // Anker stellen sicher, dass gesamter String matcht
    // Präzisere Zeichenklassen
    const pattern = /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/;
    return pattern.test(email);
}

// SICHER: Restriktive Benutzernamen-Validierung
function validateUsernameSafe(username) {
    // Nur spezifische sichere Zeichen erlauben
    // Anker stellen vollständiges Match sicher
    return /^[a-zA-Z0-9_-]{3,20}$/.test(username);
}

// SICHER: Ordentliche Telefon-Validierung
function validatePhoneSafe(phone) {
    // Bindestrich escapen oder ans Ende der Klasse setzen
    return /^[0-9\-]+$/.test(phone);

    // Oder spezifischeres Format:
    // return /^\d{3}-\d{3}-\d{4}$/.test(phone);
}

// SICHER: Nicht-gieriger Quantifizierer
function extractURLSafe(text) {
    // .*? ist nicht-gierig, matcht Minimum
    const match = text.match(/href="(.*?)"/);
    return match ? match[1] : null;

    // Noch besser - Anführungszeichen aus Klasse ausschließen:
    // const match = text.match(/href="([^"]*)"/);
}

// SICHER: Groß-/Kleinschreibungs-Behandlung
function validateCommandSafe(cmd) {
    // Case-insensitive Flag
    return /^(GET|POST|PUT|DELETE)$/i.test(cmd);
}

// SICHER: Unicode-Unterstützung
function validateNameSafe(name) {
    // Unicode-Buchstaben-Kategorie
    return /^[\p{L}\p{M}' -]+$/u.test(name);
}

// SICHER: Eingabelängen-Limits
function validateInputSafe(input, maxLength = 100) {
    if (input.length > maxLength) {
        return false;
    }
    return /^[a-zA-Z0-9_-]+$/.test(input);
}
import re
import ipaddress

# SICHER: Vollständiges String-Matching mit Ankern
def validate_ip_safe(ip):
    # Anker verwenden
    pattern = r'^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}

```java
// SICHER: Ordentliche Java-Regex-Verwendung
public class SafeValidator {

    // Verankertes Muster
    private static final Pattern EMAIL_PATTERN =
        Pattern.compile("^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$");

    public boolean validateEmail(String email) {
        // matches() verwenden, das vollständiges Match erfordert
        return EMAIL_PATTERN.matcher(email).matches();
    }

    // SICHER: Nicht-gierige Script-Entfernung
    private static final Pattern SCRIPT_PATTERN =
        Pattern.compile("<script[^>]*>.*?</script>",
                        Pattern.CASE_INSENSITIVE | Pattern.DOTALL);

    public String removeScripts(String html) {
        // Nicht-gieriges .*? matcht jeden Script-Tag einzeln
        return SCRIPT_PATTERN.matcher(html).replaceAll("");
    }

    // SICHER: Eingabevalidierung mit Grenzen
    public boolean validateUsername(String username) {
        if (username == null || username.length() > 50) {
            return false;
        }

        return username.matches("^[a-zA-Z0-9_]{3,20}$");
    }
}

Ausgenutzt in der Praxis

E-Mail-Validierungs-Bypass

Permissiver E-Mail-Regex erlaubte XSS-Payloads in "E-Mail"-Feldern.

URL-Filter-Bypass

Übermäßig permissive URL-Validierung erlaubte bösartige Umleitungen.

SQL-Injection

Eingabevalidierungs-Regex umgangen, was SQL-Injection ermöglichte.


Tools zum Testen/Ausnutzen

  • regex101 — Regex testen und debuggen.
  • RegexBuddy — Regex-Entwicklungstool.
  • Fuzzing-Tools mit bösartigen Eingabemustern.

CVE-Beispiele

  • CVEs durch Regex-Validierungs-Bypass in Webanwendungen.
  • WAF-Bypass durch permissive Regex-Regeln.

Referenzen

  1. MITRE. "CWE-625: Permissive Regular Expression." https://cwe.mitre.org/data/definitions/625.html
  2. OWASP. "Input Validation Cheat Sheet."