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

AuswirkungDetails
IntegritätUmfang: Integrität

Anwendungsdaten modifizieren - Häufige Datentypen, die angegriffen werden, sind Umgebungsvariablen, Webanwendungsparameter und HTTP-Header.
IntegritätUmfang: 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

  1. MITRE Corporation. "CWE-471: Modification of Assumed-Immutable Data (MAID)." https://cwe.mitre.org/data/definitions/471.html
  2. OWASP. "Parameter Tampering." https://owasp.org/www-community/attacks/Parameter_Tampering
  3. CAPEC-384. "Application API Message Manipulation via Man-in-the-Middle."