Modifikation von als unveränderlich angenommenen Daten (MAID)
Beschreibung
Modifikation von als unveränderlich angenommenen Daten ist eine Schwachstelle, bei der das Produkt ein als unveränderlich angenommenes Element nicht ordnungsgemäß vor Modifikation durch einen Angreifer schützt. Dies tritt auf, wenn kritische Eingaben, von denen das Programm annimmt, dass sie konstant bleiben, tatsächlich geändert werden können. Häufig verwundbare Ressourcen umfassen versteckte Formularfelder in Webanwendungen, Cookies, Umgebungsvariablen und Daten, die von Reverse-DNS-Lookups abgerufen werden. Angreifer können diese Werte modifizieren, um Sicherheitskontrollen zu umgehen oder das Anwendungsverhalten zu ändern.
Risiko
MAID-Schwachstellen ermöglichen es Angreifern, Daten zu manipulieren, denen die Anwendung vertraut. Versteckte Formularfelder, die Preise oder Benutzerrollen enthalten, können modifiziert werden, um unbefugte Rabatte oder Privilegien zu erhalten. Cookies, die den Authentifizierungsstatus speichern, können manipuliert werden, um andere Benutzer zu imitieren. Umgebungsvariablen, denen für Konfiguration vertraut wird, können manipuliert werden, um das Anwendungsverhalten zu ändern. Das Risiko ist besonders schwerwiegend, wenn die als unveränderlich angenommenen Daten Sicherheitsentscheidungen wie Authentifizierung, Autorisierung oder Preisgestaltung kontrollieren.
Lösung
Implementieren Sie Integritätsprüfungen während der Speicherung oder Übertragung durch nicht vertrauenswürdige Quellen. Speichern Sie sensible Daten an vertrauenswürdigen Orten, die vor externem Einfluss geschützt sind (serverseitige Sessions anstelle von clientseitigen Cookies). Verwenden Sie kryptographische Signaturen (HMAC), um Manipulationen an Daten zu erkennen, die nicht vertrauenswürdige Kanäle durchqueren müssen. Vertrauen Sie niemals allein auf clientseitige Validierung - validieren Sie immer auf dem Server. Vermeiden Sie die Verwendung von Umgebungsvariablen oder externen Daten für sicherheitskritische Entscheidungen ohne Verifizierung. Behandeln Sie alle Daten aus externen Quellen als potenziell modifiziert.
Häufige Auswirkungen
| Auswirkung | Details |
|---|---|
| Integrität | Umfang: Integrität Anwendungsdaten modifizieren - Häufige Datentypen, die angegriffen werden, sind Umgebungsvariablen, Webanwendungsparameter und HTTP-Header. |
| Integrität | Umfang: Integrität Unerwarteter Zustand - Angreifer können den Anwendungszustand durch Modifikation von Daten ändern, von denen die Anwendung annimmt, dass sie konstant sind. |
Beispielcode
Anfälliger Code
<!-- Anfällig: Versteckte Formularfelder die modifiziert werden können -->
<form action="/checkout" method="POST">
<!-- Anfällig: Preis kann vom Benutzer modifiziert werden -->
<input type="hidden" name="product_id" value="123">
<input type="hidden" name="price" value="99.99">
<input type="hidden" name="discount" value="0">
<!-- Anfällig: Benutzerrolle im Formular -->
<input type="hidden" name="user_role" value="customer">
<input type="submit" value="Kaufen">
</form>
<!-- Angreifer modifiziert DOM oder fängt Request ab:
price=0.01, discount=99, user_role=admin -->
# Anfällig: Vertrauen auf client-bereitgestellte Daten
from flask import Flask, request, session
app = Flask(__name__)
@app.route('/checkout', methods=['POST'])
def vulnerable_checkout():
# Anfällig: Preis aus Formular (kann modifiziert werden)
price = float(request.form.get('price'))
quantity = int(request.form.get('quantity'))
total = price * quantity
# Angreifer übermittelte price=0.01
process_payment(total)
@app.route('/admin/action', methods=['POST'])
def vulnerable_admin_action():
# Anfällig: Rolle aus Cookie (kann modifiziert werden)
user_role = request.cookies.get('role', 'guest')
# Angreifer setzt Cookie: role=admin
if user_role == 'admin':
perform_admin_action() # Unbefugter Zugriff
@app.route('/api/data')
def vulnerable_api():
# Anfällig: Vertrauen auf Client-IP aus Header (kann gefälscht werden)
client_ip = request.headers.get('X-Forwarded-For',
request.remote_addr)
if is_internal_ip(client_ip):
# Angreifer fügt Header hinzu: X-Forwarded-For: 10.0.0.1
return get_sensitive_data()
// Anfällig: Vertrauen auf veränderbares Array das von Methode zurückgegeben wird
public class VulnerablePermissions {
private String[] adminUsers = {"admin", "root", "superuser"};
// Anfällig: Gibt Referenz auf internes Array zurück
public String[] getAdminUsers() {
return adminUsers; // Aufrufer kann modifizieren!
}
public boolean isAdmin(String username) {
for (String admin : adminUsers) {
if (admin.equals(username)) {
return true;
}
}
return false;
}
}
// Angriff:
// String[] admins = permissions.getAdminUsers();
// admins[0] = "attacker"; // Jetzt ist "attacker" Admin!
<?php
// Anfällig: PHP register_globals-Stil Schwachstelle
function vulnerable_authenticate() {
// Anfällig: $authenticated könnte aus Benutzereingabe kommen
// wenn register_globals aktiviert ist oder manuelle Extraktion erfolgt
if (isset($_GET['authenticated'])) {
$authenticated = $_GET['authenticated']; // Angreifer kontrolliert!
}
if ($authenticated) {
// Angreifer übergibt ?authenticated=1
grant_access();
}
}
// Anfällig: Vertrauen auf PHP_SELF
function vulnerable_form() {
// Anfällig: PHP_SELF kann manipuliert werden
echo '<form action="' . $_SERVER['PHP_SELF'] . '">';
// Angreifer besucht: /page.php/"><script>alert(1)</script>
// Resultiert in XSS über "unveränderliche" Server-Variable
}
?>
Korrigierter Code
# Korrigiert: Serverseitige Datenvalidierung
from flask import Flask, request, session
from functools import wraps
import hmac
import hashlib
app = Flask(__name__)
app.secret_key = 'your-secret-key'
def get_product_price(product_id):
"""Preis aus serverseitiger Datenbank abrufen."""
return database.query("SELECT price FROM products WHERE id = ?", product_id)
@app.route('/checkout', methods=['POST'])
def secure_checkout():
product_id = request.form.get('product_id')
quantity = int(request.form.get('quantity'))
# Korrigiert: Preis vom Server abrufen, nicht vom Client
price = get_product_price(product_id)
if price is None:
return "Ungültiges Produkt", 400
total = price * quantity
process_payment(total)
def login_required(f):
@wraps(f)
def decorated(*args, **kwargs):
# Korrigiert: Rolle aus serverseitiger Session abrufen, nicht aus Cookie
if 'user_id' not in session:
return "Unbefugt", 401
user = database.get_user(session['user_id'])
request.user = user
return f(*args, **kwargs)
return decorated
def admin_required(f):
@wraps(f)
def decorated(*args, **kwargs):
# Korrigiert: Rolle aus Datenbank verifizieren
if not hasattr(request, 'user') or request.user.role != 'admin':
return "Verboten", 403
return f(*args, **kwargs)
return decorated
@app.route('/admin/action', methods=['POST'])
@login_required
@admin_required
def secure_admin_action():
# Rolle aus serverseitiger Session und Datenbank verifiziert
perform_admin_action()
@app.route('/api/data')
def secure_api():
# Korrigiert: X-Forwarded-For nicht direkt vertrauen
# Vertrauenswürdige Proxy-Konfiguration verwenden oder anders verifizieren
# Option 1: Tatsächliche Remote-Adresse von vertrauenswürdigem Proxy verwenden
client_ip = get_trusted_client_ip(request)
# Option 2: Authentifizierung anstelle von IP verwenden
api_key = request.headers.get('X-API-Key')
if not verify_api_key(api_key):
return "Unbefugt", 401
return get_sensitive_data()
// Korrigiert: Defensive Kopie des Arrays zurückgeben
public class SecurePermissions {
private final String[] adminUsers = {"admin", "root", "superuser"};
// Korrigiert: Kopie des Arrays zurückgeben
public String[] getAdminUsers() {
return Arrays.copyOf(adminUsers, adminUsers.length);
}
// Korrigiert: Oder unveränderbare Ansicht zurückgeben
public List<String> getAdminUsersList() {
return Collections.unmodifiableList(Arrays.asList(adminUsers));
}
// Korrigiert: Besser - interne Daten überhaupt nicht exponieren
public boolean isAdmin(String username) {
for (String admin : adminUsers) {
if (admin.equals(username)) {
return true;
}
}
return false;
}
}
<?php
// Korrigiert: Ordnungsgemäße Authentifizierung ohne Vertrauen auf Benutzereingabe
function secure_authenticate() {
session_start();
// Korrigiert: Session prüfen, nicht benutzer-kontrollierbare Variablen
if (isset($_SESSION['authenticated']) && $_SESSION['authenticated'] === true) {
grant_access();
} else {
require_login();
}
}
// Korrigiert: PHP_SELF nicht verwenden, bekannte Aktion verwenden
function secure_form() {
// Korrigiert: Explizite, bekannte Aktions-URL verwenden
$action = '/process_form.php';
echo '<form action="' . htmlspecialchars($action, ENT_QUOTES) . '">';
}
// Korrigiert: Daten signieren die durch Client gehen müssen
function create_signed_form_data($data) {
$json = json_encode($data);
$signature = hash_hmac('sha256', $json, SECRET_KEY);
return base64_encode($json . '|' . $signature);
}
function verify_signed_form_data($encoded) {
$decoded = base64_decode($encoded);
list($json, $signature) = explode('|', $decoded, 2);
// Korrigiert: Signatur verifizieren
$expected = hash_hmac('sha256', $json, SECRET_KEY);
if (!hash_equals($expected, $signature)) {
throw new SecurityException("Daten manipuliert");
}
return json_decode($json, true);
}
?>
<!-- Korrigiert: Signierte versteckte Felder -->
<form action="/checkout" method="POST">
<!-- Produktinfo vom Server signiert -->
<input type="hidden" name="signed_data"
value="eyJwcm9kdWN0X2lkIjoxMjMsInByaWNlIjo5OS45OX0=|abc123signature">
<input type="text" name="quantity" value="1">
<input type="submit" value="Kaufen">
</form>
<!-- Server verifiziert Signatur vor Verarbeitung -->
CVE-Beispiele
- CVE-2002-1757 - Authentifizierung verließ sich auf PHP_SELF-Variable, die von Angreifern manipuliert werden könnte.
- CVE-2005-1905 - Privilegieneskalation durch Modifikation von Code-Adressen, die in Treibern als unveränderlich angenommen wurden.
Referenzen
- MITRE Corporation. "CWE-471: Modification of Assumed-Immutable Data (MAID)." https://cwe.mitre.org/data/definitions/471.html
- OWASP. "Parameter Tampering." https://owasp.org/www-community/attacks/Parameter_Tampering
- CAPEC-384. "Application API Message Manipulation via Man-in-the-Middle."