Unsachgemäße Kontrolle dynamisch identifizierter Variablen
Beschreibung
Unsachgemäße Kontrolle dynamisch identifizierter Variablen tritt auf, wenn Software das Lesen von oder Schreiben in Variablen, die durch Eingabe-Strings spezifiziert werden, nicht ordnungsgemäß einschränkt. Viele Programmiersprachen bieten Mechanismen zum dynamischen Zugriff auf Variablen nach Namen zur Laufzeit (variable Variables, extract(), import_from_string, etc.). Wenn Angreifer die Variablennamen kontrollieren können, auf die zugegriffen wird, können sie unbeabsichtigte Variablen lesen oder ändern, einschließlich sicherheitskritischer wie Authentifizierungsflags, Konfigurationseinstellungen oder Zugriffskontrollparameter.
Risiko
Diese Schwachstelle ermöglicht Angreifern, den Programmzustand auf unerwartete Weise zu manipulieren. Angreifer können sicherheitsrelevante Variablen überschreiben, um Authentifizierungs- oder Autorisierungsprüfungen zu umgehen. Sie können auf sensible Variablen zugreifen, um vertrauliche Informationen zu leaken. In einigen Fällen kann das Ändern von Variablen zu Codeausführung führen, wenn Funktionszeiger oder Klassennamen betroffen sind. Der Angriff ist besonders gefährlich, weil er Variablen betrifft, von denen der Entwickler annahm, dass sie intern und vor externer Manipulation geschützt sind. Häufige Angriffsszenarien umfassen das Umgehen von Zugriffskontrollen, das Ändern von Konfigurationswerten und Path Traversal durch Variablenmanipulation.
Lösung
Vermeiden Sie die Verwendung dynamischer Variablenzugriffsmechanismen mit nicht vertrauenswürdigen Eingaben. Wenn dynamischer Variablenzugriff notwendig ist, verwenden Sie eine explizite Allowlist erlaubter Variablennamen. Verwenden Sie dedizierte Datenstrukturen (Arrays, Maps, Objekte) anstelle von einzelnen Variablen für benutzerkontrollierte Daten. Bei der Verwendung von Funktionen wie extract() geben Sie das Flag EXTR_SKIP an, um das Überschreiben existierender Variablen zu verhindern, oder besser noch, vermeiden Sie extract() vollständig. Validieren und bereinigen Sie alle Variablennamen gegen strenge Muster. Erwägen Sie architektonische Änderungen, die die Notwendigkeit für dynamischen Variablenzugriff eliminieren.
Häufige Auswirkungen
| Auswirkung | Details |
|---|---|
| Integrität | Bereich: Integrität Anwendungsdaten ändern - Angreifer können Variablen überschreiben, um den Anwendungszustand oder das Verhalten zu ändern. |
| Integrität | Bereich: Integrität Unbefugten Code oder Befehle ausführen - In einigen Kontexten können modifizierte Variablen zu Codeausführung führen. |
| Vertraulichkeit | Bereich: Vertraulichkeit Anwendungsdaten lesen - Angreifer können über dynamischen Zugriff auf sensible Variablenwerte zugreifen. |
| Zugriffskontrolle | Bereich: Zugriffskontrolle Schutzmechanismus umgehen - Sicherheitsflags und Zugriffskontrollvariablen können überschrieben werden. |
Beispielcode + Lösungscode
Verwundbarer Code
// Verwundbar: extract() überschreibt lokale Variablen
<?php
function vulnerable_login($username, $password) {
$isAdmin = false; // Wichtiges Sicherheitsflag
// Verwundbar: extract() erstellt Variablen aus POST-Daten
extract($_POST);
// Zugangsdaten prüfen
$user = authenticate($username, $password);
if ($isAdmin) { // Angreifer kann isAdmin=true in POST setzen!
grantAdminAccess($user);
}
return $user;
}
// Angriff: POST-Daten mit isAdmin=true umgeht Authentifizierung
// POST: username=hacker&password=falsch&isAdmin=true
?>
// Verwundbar: Variable Variablen
<?php
$adminPassword = "secret123";
$userInput = "adminPassword"; // Von Benutzer
// Verwundbar: Variable Variable greift auf jede Variable zu
$value = $userInput; // Gibt "secret123" zurück
// Oder zum Schreiben:
$varName = $_GET['name'];
$varValue = $_GET['value'];
$varName = $varValue; // Kann jede Variable überschreiben!
?>
Sicherer Code
// Behoben: Erlaubte Variablen whitelisten
<?php
function fixed_login($username, $password) {
$isAdmin = false;
// Behoben: Nur spezifische, erlaubte Schlüssel extrahieren
$allowed = ['username', 'password'];
$filtered = array_intersect_key($_POST, array_flip($allowed));
// Oder manuell zuweisen
$username = $_POST['username'] ?? '';
$password = $_POST['password'] ?? '';
$user = authenticate($username, $password);
// isAdmin kann nur durch ordnungsgemäße Autorisierung gesetzt werden
if ($user && $user->hasAdminRole()) {
$isAdmin = true;
grantAdminAccess($user);
}
return $user;
}
?>
// Behoben: Variable Variablen vermeiden, Arrays verwenden
<?php
// Anstelle von einzelnen Variablen ein Array verwenden
$config = [
'adminPassword' => 'secret123',
'apiKey' => 'xyz789'
];
// Nur Zugriff auf spezifische Schlüssel erlauben
$allowedKeys = ['theme', 'language', 'timezone'];
function getSetting($key, $config, $allowedKeys) {
// Behoben: Whitelist-Prüfung
if (!in_array($key, $allowedKeys)) {
throw new InvalidArgumentException("Unbekannte Einstellung: $key");
}
return $config[$key] ?? null;
}
?>
# Behoben: Explizites Konfigurations-Dictionary verwenden
class Config:
ALLOWED_KEYS = {'theme', 'language', 'timezone', 'page_size'}
def __init__(self):
self._settings = {
'theme': 'light',
'language': 'de',
'timezone': 'UTC',
'page_size': 20
}
def set(self, key, value):
# Behoben: Nur bekannte Einstellungen erlauben
if key not in self.ALLOWED_KEYS:
raise ValueError(f"Unbekannte Einstellung: {key}")
self._settings[key] = value
def get(self, key):
if key not in self.ALLOWED_KEYS:
raise ValueError(f"Unbekannte Einstellung: {key}")
return self._settings.get(key)
// Behoben: Eigenschaftsnamen validieren
function fixedSetProperty(obj, key, value) {
// Verbotene Eigenschaften
const FORBIDDEN = ['__proto__', 'constructor', 'prototype'];
// Behoben: Prototype Pollution verhindern
if (FORBIDDEN.includes(key)) {
throw new Error(`Kann Eigenschaft nicht setzen: ${key}`);
}
// Optional: Erlaubte Eigenschaften whitelisten
const ALLOWED = ['theme', 'language', 'timezone'];
if (!ALLOWED.includes(key)) {
throw new Error(`Unbekannte Eigenschaft: ${key}`);
}
obj[key] = value;
}
// Besser: Map für dynamische Schlüssel verwenden
const userSettings = new Map();
function setUserSetting(key, value) {
const ALLOWED = ['theme', 'language', 'timezone'];
if (!ALLOWED.includes(key)) {
throw new Error(`Unbekannte Einstellung: ${key}`);
}
userSettings.set(key, value);
}
CVE-Beispiele
- CVE-2006-7135: extract()-Schwachstelle ermöglichte beliebige Dateieinbindung.
- CVE-2006-7079: extract() wurde verwendet, um Path-Traversal-Angriff zu ermöglichen.
- CVE-2009-0422: Dynamische Variablenauswertung ermöglichte Remote File Inclusion.
- CVE-2007-2431: Dynamische Variablenauswertung für Cross-Site-Scripting verwendet.
- CVE-2006-4019: Schwachstelle ermöglichte Lesen und Ändern von Benutzer-Anhängen.
Verwandte CWEs
- CWE-99: Unsachgemäße Kontrolle von Ressourcen-Identifikatoren ('Resource Injection') (Eltern)
- CWE-913: Unsachgemäße Kontrolle dynamisch verwalteter Code-Ressourcen (verwandt)
- CWE-621: Variablen-Extraktionsfehler (verwandt)
- CWE-627: Dynamische Variablenauswertung (verwandt)
Referenzen
- MITRE Corporation. "CWE-914: Improper Control of Dynamically-Identified Variables." https://cwe.mitre.org/data/definitions/914.html
- OWASP. "Mass Assignment Cheat Sheet." https://cheatsheetseries.owasp.org/cheatsheets/Mass_Assignment_Cheat_Sheet.html
- PHP Documentation. "Variable variables." https://www.php.net/manual/en/language.variables.variable.php