Unsachgemäße Validierung unsicherer Äquivalenz in der Eingabe
Beschreibung
Unsachgemäße Validierung unsicherer Äquivalenz in der Eingabe tritt auf, wenn ein Produkt eine Eingabe als Ressourcenbezeichner akzeptiert, aber nicht validiert, ob sie einem potenziell gefährlichen Wert äquivalent ist. Angreifer können manchmal Eingabevalidierungsschemata umgehen, indem sie Eingaben finden, die sicher erscheinen, aber gefährlich sind, wenn sie auf einer niedrigeren Ebene oder von einer nachgelagerten Komponente verarbeitet werden. Ein praktisches Beispiel: XSS-Filter, die groß-/kleinschreibungssensitiven Abgleich für <script>-Tags verwenden, können mit <ScrIpT> umgangen werden, da HTML-Rendering groß-/kleinschreibungsunempfindlich ist.
Risiko
Unsichere Äquivalenzumgehung hat schwerwiegende Sicherheitsauswirkungen. Eingabefilter können umgangen werden. XSS-Angriffe können erfolgreich sein. Path Traversal ist möglich. Zugriffskontrollen umgehbar. Injection-Angriffe werden ermöglicht. Sicherheitsrichtlinien unwirksam. Denylists werden nutzlos. Nachgelagerte Verarbeitung wird ausgenutzt.
Lösung
Verwenden Sie die Validierung nach dem Prinzip "bekannt Gutes akzeptieren": Pflegen Sie strikte Allowlists akzeptabler Eingaben, die den Spezifikationen entsprechen. Lehnen Sie nicht-konforme Daten ab. Berücksichtigen Sie Länge, Typ, Wertebereiche, Syntax und Geschäftslogik. Normalisieren Sie Eingaben vor der Validierung, wo angemessen. Verwenden Sie groß-/kleinschreibungsunempfindliche Vergleiche für groß-/kleinschreibungsunempfindliche Protokolle. Denylists allein sind unzureichend - sie können nicht alle Äquivalenzen abdecken.
Häufige Auswirkungen
| Auswirkung | Details |
|---|---|
| Sonstiges | Bereich: Sonstiges Sicherheitsumgehung abhängig von der Ausnutzungsmethode. |
| Zugriffskontrolle | Bereich: Zugriffskontrolle Filter und Einschränkungen können umgangen werden. |
| Integrität | Bereich: Integrität Bösartige Eingaben können nachgelagerte Komponenten erreichen. |
Beispielcode und Lösung
Verwundbarer Code
# VERWUNDBAR: Groß-/kleinschreibungssensitiver XSS-Filter
import re
# VERWUNDBAR: Groß-/kleinschreibungssensitive Blockliste
DANGEROUS_TAGS = ['<script>', '</script>', '<iframe>', '<object>']
def vulnerable_xss_filter(input_html):
"""XSS filtern - VERWUNDBAR gegenüber Groß-/Kleinschreibungsvariation."""
result = input_html
# VERWUNDBAR: Groß-/kleinschreibungssensitiver Abgleich
for tag in DANGEROUS_TAGS:
result = result.replace(tag, '')
return result
# Angreifer verwendet: <ScRiPt>alert(1)</sCrIpT>
# Filter erkennt gemischte Schreibweise nicht
# Browser führt es trotzdem aus (HTML ist groß-/kleinschreibungsunempfindlich)
# VERWUNDBAR: Groß-/kleinschreibungssensitive Dateierweiterungsprüfung
def vulnerable_file_upload(filename):
"""Dateierweiterung prüfen - VERWUNDBAR gegenüber Groß-/Kleinschreibungsumgehung."""
BLOCKED_EXTENSIONS = ['.exe', '.bat', '.cmd', '.ps1']
# VERWUNDBAR: Groß-/kleinschreibungssensitiver Vergleich
for ext in BLOCKED_EXTENSIONS:
if filename.endswith(ext):
return False
return True # Upload erlauben
# Angreifer lädt hoch: malware.EXE oder malware.Exe
# Filter erkennt Großbuchstaben-Erweiterungen nicht
# VERWUNDBAR: URL-Kodierung nicht berücksichtigt
def vulnerable_path_check(path):
"""Auf Directory Traversal prüfen - VERWUNDBAR gegenüber Kodierungsumgehung."""
# VERWUNDBAR: Prüft nur literales "../"
if '../' in path:
return False
return True
# Angreifer verwendet: %2e%2e%2f (URL-kodiertes ../)
# Oder: ..%2f (teilweise Kodierung)
# Oder: ..\ (Backslash unter Windows)
// VERWUNDBAR: JavaScript mit Äquivalenzproblemen
// VERWUNDBAR: Groß-/kleinschreibungssensitive Hostname-Prüfung
function vulnerableCheckRedirect(url) {
// VERWUNDBAR: Groß-/kleinschreibungssensitiver Vergleich
if (url.includes('malicious.com')) {
return false;
}
return true;
// Angreifer verwendet: MALICIOUS.COM oder Malicious.Com
// DNS ist groß-/kleinschreibungsunempfindlich, Weiterleitung gelingt
}
// VERWUNDBAR: Leerzeichen-Äquivalenz nicht berücksichtigt
function vulnerableValidateUrl(url) {
const allowedHosts = ['example.com', 'trusted.com'];
// URL parsen
const parsed = new URL(url);
// VERWUNDBAR: Berücksichtigt keine Leerzeichen-Varianten
if (!allowedHosts.includes(parsed.hostname)) {
return false;
}
return true;
// Angreifer verwendet: "https://evil.com%20.example.com"
// Oder kodierte Leerzeichen, die das Parsing beeinflussen
}
// VERWUNDBAR: Unicode-Äquivalenz
function vulnerableUsernameCheck(username) {
const blockedUsers = ['admin', 'root', 'administrator'];
// VERWUNDBAR: Normalisiert kein Unicode
if (blockedUsers.includes(username.toLowerCase())) {
return false;
}
return true;
// Angreifer verwendet: "ɑdmin" (lateinisches Alpha statt 'a')
// Oder: "аdmin" (kyrillisches 'а' statt lateinischem 'a')
}
// VERWUNDBAR: C mit Äquivalenzumgehungsproblemen
#include <string.h>
#include <ctype.h>
// VERWUNDBAR: Groß-/kleinschreibungssensitive Befehlsprüfung
int vulnerable_check_command(const char* cmd) {
// VERWUNDBAR: Blockiert nur exakte Kleinbuchstabenübereinstimmung
if (strcmp(cmd, "shutdown") == 0 ||
strcmp(cmd, "reboot") == 0 ||
strcmp(cmd, "format") == 0) {
return 0; // Blockiert
}
return 1; // Erlaubt
// Angreifer verwendet: "SHUTDOWN", "Shutdown", "sHuTdOwN"
}
// VERWUNDBAR: Pfadprüfung ohne Normalisierung
int vulnerable_check_path(const char* path) {
// VERWUNDBAR: Prüft nur literales Muster
if (strstr(path, "..") != NULL) {
return 0; // Blockiert
}
if (strstr(path, "/etc/") != NULL) {
return 0; // Blockiert
}
return 1;
// Angreifer verwendet:
// - "....//etc/passwd" (doppelte Punkte)
// - "/etc//passwd" (doppelte Schrägstriche)
// - "/etc/./passwd" (aktuelle Verzeichnisreferenz)
}
// VERWUNDBAR: Erweiterungsprüfung ohne Groß-/Kleinschreibungsnormalisierung
int vulnerable_check_extension(const char* filename) {
const char* ext = strrchr(filename, '.');
if (ext == NULL) return 0;
// VERWUNDBAR: Groß-/kleinschreibungssensitiver Vergleich
if (strcmp(ext, ".php") == 0 ||
strcmp(ext, ".asp") == 0 ||
strcmp(ext, ".jsp") == 0) {
return 0; // Blockiert
}
return 1;
// Angreifer lädt hoch: shell.PHP, shell.Php, shell.pHp
}
Sichere Lösung
# SICHER: Ordnungsgemäße Äquivalenzbehandlung
import re
import html
import urllib.parse
import unicodedata
# SICHER: Groß-/kleinschreibungsunempfindlicher XSS-Filter mit Normalisierung
def secure_xss_filter(input_html):
"""XSS mit ordnungsgemäßer Groß-/Kleinschreibungsbehandlung filtern."""
# SICHER: Allowlist-Ansatz statt Denylist verwenden
# Nur bestimmte sichere Tags erlauben
# Ansatz 1: Alles HTML escapen
escaped = html.escape(input_html)
return escaped
# Ansatz 2: Wenn HTML benötigt, ordnungsgemäßen Sanitizer verwenden
# import bleach
# return bleach.clean(input_html, tags=['p', 'b', 'i', 'em', 'strong'])
# SICHER: Groß-/kleinschreibungsunempfindliche Dateierweiterungsprüfung
def secure_file_upload(filename):
"""Dateierweiterung mit Groß-/Kleinschreibungsnormalisierung prüfen."""
ALLOWED_EXTENSIONS = {'.jpg', '.jpeg', '.png', '.gif', '.pdf', '.txt'}
# SICHER: Vor Prüfung in Kleinbuchstaben normalisieren
normalized = filename.lower()
# SICHER: Erweiterung korrekt extrahieren
if '.' not in normalized:
return False
ext = '.' + normalized.rsplit('.', 1)[-1]
# SICHER: Allowlist verwenden, nicht Denylist
if ext not in ALLOWED_EXTENSIONS:
return False
# SICHER: Auch auf doppelte Erweiterungen prüfen
if normalized.count('.') > 1:
# Zusätzliche Prüfung für Dateien wie "image.jpg.php"
parts = normalized.split('.')
for part in parts[:-1]:
if part in ['php', 'asp', 'jsp', 'exe', 'bat']:
return False
return True
# SICHER: Pfadprüfung mit Normalisierung
import os
def secure_path_check(path, base_dir):
"""Pfad mit ordnungsgemäßer Normalisierung prüfen."""
# SICHER: Zuerst URL-dekodieren
decoded = urllib.parse.unquote(path)
# SICHER: Pfad normalisieren (löst .., ., mehrfache Schrägstriche auf)
normalized = os.path.normpath(decoded)
# SICHER: In absoluten Pfad auflösen
full_path = os.path.abspath(os.path.join(base_dir, normalized))
base_path = os.path.abspath(base_dir)
# SICHER: Pfad ist unter Basisverzeichnis
if not full_path.startswith(base_path + os.sep):
return False
return True
# SICHER: Unicode-Normalisierung für Benutzername
def secure_username_check(username):
"""Benutzername mit Unicode-Normalisierung prüfen."""
# SICHER: Unicode normalisieren (NFKC normalisiert Ähnlichkeiten)
normalized = unicodedata.normalize('NFKC', username)
# SICHER: Groß-/kleinschreibungsunempfindlicher Vergleich
normalized = normalized.lower()
# SICHER: Gegen blockierte Benutzer prüfen
blocked_users = {'admin', 'root', 'administrator', 'system'}
if normalized in blocked_users:
return False
# SICHER: Zusätzliche Prüfungen für verwechselbare Zeichen
# Nicht-ASCII-Zeichen entfernen, die Verwechslungen sein könnten
ascii_only = normalized.encode('ascii', 'ignore').decode('ascii')
if ascii_only != normalized:
# Enthält Nicht-ASCII - zusätzliche Prüfung
if ascii_only in blocked_users:
return False # "ɑdmin" normalisiert sich zu "admin"
return True
// SICHER: JavaScript mit ordnungsgemäßer Äquivalenzbehandlung
// SICHER: Groß-/kleinschreibungsunempfindliche Hostname-Prüfung
function secureCheckRedirect(url) {
try {
const parsed = new URL(url);
// SICHER: Hostname in Kleinbuchstaben normalisieren
const hostname = parsed.hostname.toLowerCase();
// SICHER: Allowlist statt Denylist verwenden
const allowedHosts = ['example.com', 'trusted.com', 'api.example.com'];
if (!allowedHosts.includes(hostname)) {
return false;
}
// SICHER: Auch Protokoll prüfen
if (parsed.protocol !== 'https:') {
return false;
}
return true;
} catch (e) {
// Ungültige URL
return false;
}
}
// SICHER: URL-Validierung mit Normalisierung
function secureValidateUrl(url) {
try {
// SICHER: URL normalisieren
const parsed = new URL(url);
// SICHER: Auf Leerzeichen im Hostname prüfen (verdächtig)
if (/\s/.test(parsed.hostname)) {
return false;
}
// SICHER: Hostname normalisieren und prüfen
const hostname = parsed.hostname.toLowerCase().trim();
const allowedHosts = ['example.com', 'trusted.com'];
// SICHER: Exakte Übereinstimmung oder Subdomain-Übereinstimmung
for (const allowed of allowedHosts) {
if (hostname === allowed ||
hostname.endsWith('.' + allowed)) {
return true;
}
}
return false;
} catch (e) {
return false;
}
}
// SICHER: Benutzername-Prüfung mit Normalisierung
function secureUsernameCheck(username) {
// SICHER: Unicode mit String.normalize() normalisieren
const normalized = username.normalize('NFKC').toLowerCase();
const blockedUsers = new Set(['admin', 'root', 'administrator', 'system']);
if (blockedUsers.has(normalized)) {
return false;
}
// SICHER: Nur erlaubte Zeichen enthalten
if (!/^[a-z0-9_-]+$/.test(normalized)) {
// Enthält Zeichen außerhalb von Basis-ASCII
// Könnten Unicode-Verwechslungen sein
return false;
}
return true;
}
// SICHER: C mit ordnungsgemäßer Äquivalenzbehandlung
#include <string.h>
#include <ctype.h>
#include <stdbool.h>
#include <stdlib.h>
// SICHER: Groß-/kleinschreibungsunempfindliche Befehlsprüfung
bool secure_check_command(const char* cmd) {
// SICHER: In Kleinbuchstaben für Vergleich konvertieren
char* lower = strdup(cmd);
if (lower == NULL) return false;
for (char* p = lower; *p; p++) {
*p = tolower(*p);
}
// SICHER: Allowlist-Ansatz verwenden
const char* allowed_commands[] = {"list", "status", "help", "info"};
bool allowed = false;
for (size_t i = 0; i < sizeof(allowed_commands)/sizeof(allowed_commands[0]); i++) {
if (strcmp(lower, allowed_commands[i]) == 0) {
allowed = true;
break;
}
}
free(lower);
return allowed;
}
// SICHER: Pfadprüfung mit Normalisierung
bool secure_check_path(const char* path, const char* base_dir,
char* result, size_t result_size) {
// SICHER: Puffer für normalisierten Pfad allokieren
char* normalized = realpath(path, NULL);
if (normalized == NULL) {
// Pfad existiert nicht oder ist ungültig
return false;
}
// SICHER: Kanonisches Basisverzeichnis ermitteln
char* base_canonical = realpath(base_dir, NULL);
if (base_canonical == NULL) {
free(normalized);
return false;
}
// SICHER: Normalisierter Pfad beginnt mit Basisverzeichnis
size_t base_len = strlen(base_canonical);
bool safe = (strncmp(normalized, base_canonical, base_len) == 0) &&
(normalized[base_len] == '/' || normalized[base_len] == '\0');
if (safe && result != NULL) {
strncpy(result, normalized, result_size - 1);
result[result_size - 1] = '\0';
}
free(normalized);
free(base_canonical);
return safe;
}
// SICHER: Erweiterungsprüfung mit Groß-/Kleinschreibungsnormalisierung
bool secure_check_extension(const char* filename) {
const char* ext = strrchr(filename, '.');
if (ext == NULL) return false;
// SICHER: Erweiterung in Kleinbuchstaben konvertieren
char lower_ext[16];
size_t i;
for (i = 0; ext[i] && i < sizeof(lower_ext) - 1; i++) {
lower_ext[i] = tolower(ext[i]);
}
lower_ext[i] = '\0';
// SICHER: Allowlist sicherer Erweiterungen verwenden
const char* safe_extensions[] = {".txt", ".pdf", ".jpg", ".jpeg", ".png", ".gif"};
for (size_t j = 0; j < sizeof(safe_extensions)/sizeof(safe_extensions[0]); j++) {
if (strcmp(lower_ext, safe_extensions[j]) == 0) {
return true;
}
}
return false;
}
// SICHER: Hilfsfunktion für groß-/kleinschreibungsunempfindlichen Zeichenkettenvergleich
int strcasecmp_safe(const char* s1, const char* s2) {
while (*s1 && *s2) {
int c1 = tolower((unsigned char)*s1);
int c2 = tolower((unsigned char)*s2);
if (c1 != c2) return c1 - c2;
s1++;
s2++;
}
return tolower((unsigned char)*s1) - tolower((unsigned char)*s2);
}
CVE-Beispiele
- CVE-2021-39155: Hostname-Vergleich mit groß-/kleinschreibungssensitivem Abgleich umging Autorisierungsprüfungen.
- CVE-2020-11053: HTML-kodierte Leerzeichen umgingen Weiterleitungs-URL-Validierung.
- CVE-2005-0269: Datei-Upload-Filter prüfte nur Kleinbuchstaben-Erweiterungen, was Umgehung mit Großbuchstaben ermöglichte.
- CVE-2001-1238: Prozessnamen mit Großbuchstaben könnten vom Filter nicht beendet werden.
- CVE-2004-2214: Gemischt-geschriebene URIs umgingen Zugriffsbeschränkungen.
Verwandte CWEs
- CWE-20: Unsachgemäße Eingabevalidierung (übergeordnet)
- CWE-41: Unsachgemäße Auflösung von Pfadäquivalenz (verwandt)
- CWE-178: Unsachgemäße Behandlung von Groß-/Kleinschreibung (verwandt)
- CWE-1215: Datenvalidierungsprobleme (Kategorie)
Referenzen
- MITRE Corporation. "CWE-1289: Improper Validation of Unsafe Equivalence in Input." https://cwe.mitre.org/data/definitions/1289.html
- OWASP. "Input Validation Cheat Sheet"
- Unicode Consortium. "Unicode Security Considerations"