Übermäßig tiefe Verschachtelung

Beschreibung

Übermäßig tiefe Verschachtelung tritt auf, wenn Code eine aufrufbare Einheit oder eine andere Codegruppierung enthält, in der die Verschachtelung (Verzweigungstiefe) zu tief ist. Tiefe Verschachtelung entsteht durch mehrere Ebenen verschachtelter Kontrollstrukturen wie if-Anweisungen, Schleifen, try-catch-Blöcke und switch-Anweisungen. Code mit übermäßiger Verschachtelung ist schwer zu lesen, zu verstehen, zu testen und zu warten, wodurch Sicherheitslücken schwerer zu erkennen sind und die Wahrscheinlichkeit steigt, bei der Wartung neue Fehler einzuführen.

Risiko

Übermäßig tiefe Verschachtelung hat erhebliche indirekte Sicherheitsauswirkungen. Sicherheitskritische Logik, die in tiefer Verschachtelung vergraben ist, kann übersehen werden. Prüfer können den Überblick über Bedingungen auf tiefen Ebenen verlieren. Das Testen aller Pfade durch tief verschachtelten Code ist unpraktisch. Randfälle auf tiefen Verschachtelungsebenen werden oft nicht getestet. Wartungsänderungen sind fehleranfällig, wenn der Kontext verloren geht. Refactoring-Risiken sind aufgrund komplexen Zustands höher. Sicherheitsinvarianten sind über Verschachtelungsebenen hinweg schwer zu verifizieren. Statische Analysetools können weniger genaue Ergebnisse liefern.

Lösung

Legen Sie maximale Verschachtelungstiefenschwellen fest (üblicherweise 3-4 Ebenen). Verwenden Sie frühe Rückgaben (Guard Clauses), um die Verschachtelung zu reduzieren. Extrahieren Sie tief verschachtelten Code in separate Funktionen. Invertieren Sie Bedingungen, um else-Zweige zu reduzieren. Verwenden Sie switch/case oder Lookup-Tabellen anstelle von verschachtelten if-else. Wenden Sie das "Fail Fast"-Muster für Validierung an. Flachen Sie verschachtelte Schleifen mit Iterator-Funktionen ab. Verwenden Sie Polymorphismus, um Typprüfungsverschachtelung zu eliminieren. Automatisieren Sie Verschachtelungstiefenprüfungen in CI/CD. Refactoren Sie sicherheitskritischen tief verschachtelten Code zuerst.

Häufige Auswirkungen

AuswirkungDetails
SonstigesBereich: Sonstiges

Reduzierte Wartbarkeit – Erschwert die Wartung des Produkts und beeinträchtigt indirekt die Sicherheit, indem es schwieriger oder zeitaufwändiger wird, Schwachstellen zu finden und zu beheben.
SonstigesBereich: Sonstiges

Erhöhte analytische Komplexität – Tiefe Verschachtelung erschwert die Codeanalyse und kann das Einführen von Schwachstellen erleichtern.

Beispielcode und Lösung

Verwundbarer Code

// VERWUNDBAR: Übermäßige Verschachtelungstiefe (7+ Ebenen)

public class DeepNestingExample {

    public ProcessResult processOrder(Order order, User user, Context context) {
        ProcessResult result = new ProcessResult();

        // Ebene 1
        if (order != null) {
            // Ebene 2
            if (user != null) {
                // Ebene 3
                if (user.isActive()) {
                    // Ebene 4
                    if (order.hasItems()) {
                        // Ebene 5
                        for (Item item : order.getItems()) {
                            // Ebene 6
                            if (item.isInStock()) {
                                // Ebene 7
                                if (item.getPrice() > 0) {
                                    // Ebene 8
                                    if (user.hasPermission("purchase")) {
                                        // Ebene 9
                                        try {
                                            // Ebene 10
                                            if (context.isSecure()) {
                                                // Ebene 11
                                                if (validatePayment(user, order)) {
                                                    // Bestellung tatsächlich verarbeiten
                                                    // Sicherheitsprüfung hier nahezu unmöglich!
                                                    result.setSuccess(true);
                                                } else {
                                                    result.setError("payment_failed");
                                                }
                                            } else {
                                                result.setError("insecure_context");
                                            }
                                        } catch (Exception e) {
                                            result.setError("exception: " + e.getMessage());
                                        }
                                    } else {
                                        result.setError("no_permission");
                                    }
                                } else {
                                    result.setError("invalid_price");
                                }
                            } else {
                                result.setError("out_of_stock");
                            }
                        }
                    } else {
                        result.setError("no_items");
                    }
                } else {
                    result.setError("user_inactive");
                }
            } else {
                result.setError("null_user");
            }
        } else {
            result.setError("null_order");
        }

        return result;
    }
}
# VERWUNDBAR: Python mit übermäßiger Verschachtelung

def process_transaction(transaction, account, config):
    """Transaktion mit tief verschachtelter Logik verarbeiten."""

    # Ebene 1
    if transaction:
        # Ebene 2
        if transaction.is_valid():
            # Ebene 3
            if account:
                # Ebene 4
                if account.is_active():
                    # Ebene 5
                    if transaction.type in ['deposit', 'withdrawal', 'transfer']:
                        # Ebene 6
                        if transaction.type == 'withdrawal':
                            # Ebene 7
                            if account.balance >= transaction.amount:
                                # Ebene 8
                                if transaction.amount <= config.max_withdrawal:
                                    # Ebene 9
                                    if not account.is_frozen:
                                        # Ebene 10
                                        try:
                                            # Ebene 11
                                            if verify_signature(transaction):
                                                # Ebene 12!
                                                if not is_suspicious(transaction):
                                                    # Endlich etwas tun
                                                    return execute_withdrawal(
                                                        account, transaction
                                                    )
                                                else:
                                                    return Error("suspicious_activity")
                                            else:
                                                return Error("invalid_signature")
                                        except Exception as e:
                                            return Error(f"exception: {e}")
                                    else:
                                        return Error("account_frozen")
                                else:
                                    return Error("exceeds_max_withdrawal")
                            else:
                                return Error("insufficient_funds")
                        elif transaction.type == 'deposit':
                            # Ein weiterer tief verschachtelter Block...
                            pass
                        elif transaction.type == 'transfer':
                            # Noch ein tief verschachtelter Block...
                            pass
                    else:
                        return Error("invalid_transaction_type")
                else:
                    return Error("account_inactive")
            else:
                return Error("null_account")
        else:
            return Error("invalid_transaction")
    else:
        return Error("null_transaction")
// VERWUNDBAR: JavaScript mit übermäßiger Callback-Verschachtelung (Callback Hell)

function processUserRequest(userId, requestData, callback) {
    // Ebene 1: Benutzer abrufen
    getUser(userId, function(err, user) {
        if (err) {
            callback(err);
        } else {
            // Ebene 2: Benutzer validieren
            validateUser(user, function(err, isValid) {
                if (err) {
                    callback(err);
                } else if (isValid) {
                    // Ebene 3: Berechtigungen prüfen
                    checkPermissions(user, requestData.resource, function(err, hasPermission) {
                        if (err) {
                            callback(err);
                        } else if (hasPermission) {
                            // Ebene 4: Ressource abrufen
                            getResource(requestData.resource, function(err, resource) {
                                if (err) {
                                    callback(err);
                                } else {
                                    // Ebene 5: Anfrage validieren
                                    validateRequest(requestData, resource, function(err, valid) {
                                        if (err) {
                                            callback(err);
                                        } else if (valid) {
                                            // Ebene 6: Anfrage verarbeiten
                                            processRequest(user, resource, requestData, function(err, result) {
                                                if (err) {
                                                    callback(err);
                                                } else {
                                                    // Ebene 7: Protokollieren und antworten
                                                    logActivity(user, requestData, result, function(err) {
                                                        if (err) {
                                                            callback(err);
                                                        } else {
                                                            // Endlich fertig
                                                            callback(null, result);
                                                        }
                                                    });
                                                }
                                            });
                                        } else {
                                            callback(new Error('Invalid request'));
                                        }
                                    });
                                }
                            });
                        } else {
                            callback(new Error('Permission denied'));
                        }
                    });
                } else {
                    callback(new Error('Invalid user'));
                }
            });
        }
    });
}

Sichere Lösung

// SICHER: Flache Struktur mit Guard Clauses und extrahierten Methoden

public class FlatStructureExample {

    /**
     * Bestellung mit maximaler Verschachtelungstiefe von 2 verarbeiten.
     */
    public ProcessResult processOrder(Order order, User user, Context context) {
        // Guard Clauses – frühzeitig fehlschlagen
        ProcessResult validationResult = validateOrderInputs(order, user, context);
        if (!validationResult.isSuccess()) {
            return validationResult;
        }

        // Jedes Element verarbeiten
        return processOrderItems(order, user, context);
    }

    private ProcessResult validateOrderInputs(Order order, User user, Context context) {
        if (order == null) {
            return ProcessResult.error("null_order");
        }
        if (user == null) {
            return ProcessResult.error("null_user");
        }
        if (!user.isActive()) {
            return ProcessResult.error("user_inactive");
        }
        if (!order.hasItems()) {
            return ProcessResult.error("no_items");
        }
        if (!context.isSecure()) {
            return ProcessResult.error("insecure_context");
        }
        return ProcessResult.success();
    }

    private ProcessResult processOrderItems(Order order, User user, Context context) {
        for (Item item : order.getItems()) {
            ProcessResult itemResult = processItem(item, user);
            if (!itemResult.isSuccess()) {
                return itemResult;
            }
        }

        // Alle Elemente gültig, Zahlung verarbeiten
        return processPayment(user, order);
    }

    private ProcessResult processItem(Item item, User user) {
        if (!item.isInStock()) {
            return ProcessResult.error("out_of_stock");
        }
        if (item.getPrice() <= 0) {
            return ProcessResult.error("invalid_price");
        }
        if (!user.hasPermission("purchase")) {
            return ProcessResult.error("no_permission");
        }
        return ProcessResult.success();
    }

    private ProcessResult processPayment(User user, Order order) {
        try {
            if (!validatePayment(user, order)) {
                return ProcessResult.error("payment_failed");
            }
            return ProcessResult.success();
        } catch (Exception e) {
            return ProcessResult.error("exception: " + e.getMessage());
        }
    }
}
# SICHER: Python mit flacher Struktur und frühen Rückgaben

def process_transaction(transaction, account, config):
    """Transaktion mit flacher, lesbarer Struktur verarbeiten."""

    # Eingaben validieren (Guard Clauses)
    validation_error = validate_transaction_inputs(transaction, account)
    if validation_error:
        return validation_error

    # An typspezifischen Handler weiterleiten
    handlers = {
        'withdrawal': process_withdrawal,
        'deposit': process_deposit,
        'transfer': process_transfer,
    }

    handler = handlers.get(transaction.type)
    if not handler:
        return Error("invalid_transaction_type")

    return handler(transaction, account, config)


def validate_transaction_inputs(transaction, account):
    """Grundlegende Eingaben validieren. Gibt Fehler oder None zurück."""
    if not transaction:
        return Error("null_transaction")

    if not transaction.is_valid():
        return Error("invalid_transaction")

    if not account:
        return Error("null_account")

    if not account.is_active():
        return Error("account_inactive")

    return None


def process_withdrawal(transaction, account, config):
    """Abhebung mit flacher Struktur verarbeiten."""

    # Vorbedingungen prüfen
    if account.balance < transaction.amount:
        return Error("insufficient_funds")

    if transaction.amount > config.max_withdrawal:
        return Error("exceeds_max_withdrawal")

    if account.is_frozen:
        return Error("account_frozen")

    # Sicherheit verifizieren
    if not verify_signature(transaction):
        return Error("invalid_signature")

    if is_suspicious(transaction):
        return Error("suspicious_activity")

    # Ausführen (einziger Teil, der eine Exception werfen kann)
    try:
        return execute_withdrawal(account, transaction)
    except Exception as e:
        return Error(f"exception: {e}")


def process_deposit(transaction, account, config):
    """Einzahlung mit flacher Struktur verarbeiten."""

    # Einzahlungsspezifische Regeln validieren
    if transaction.amount > config.max_deposit:
        return Error("exceeds_max_deposit")

    if transaction.source not in config.approved_sources:
        return Error("unapproved_source")

    # Ausführen
    try:
        return execute_deposit(account, transaction)
    except Exception as e:
        return Error(f"exception: {e}")


def process_transfer(transaction, account, config):
    """Überweisung mit flacher Struktur verarbeiten."""

    # Überweisungsspezifische Regeln validieren
    if not transaction.destination:
        return Error("missing_destination")

    if not validate_destination(transaction.destination):
        return Error("invalid_destination")

    if account.balance < transaction.amount:
        return Error("insufficient_funds")

    # Ausführen
    try:
        return execute_transfer(account, transaction)
    except Exception as e:
        return Error(f"exception: {e}")
// SICHER: JavaScript mit async/await anstelle von Callback-Verschachtelung

async function processUserRequest(userId, requestData) {
    // Schritt 1: Benutzer abrufen und validieren
    const user = await getUser(userId);
    const userValidation = await validateUser(user);
    if (!userValidation.isValid) {
        throw new Error('Invalid user');
    }

    // Schritt 2: Berechtigungen prüfen
    const hasPermission = await checkPermissions(user, requestData.resource);
    if (!hasPermission) {
        throw new Error('Permission denied');
    }

    // Schritt 3: Ressource abrufen und validieren
    const resource = await getResource(requestData.resource);
    const requestValid = await validateRequest(requestData, resource);
    if (!requestValid) {
        throw new Error('Invalid request');
    }

    // Schritt 4: Verarbeiten und protokollieren
    const result = await processRequest(user, resource, requestData);
    await logActivity(user, requestData, result);

    return result;
}

// Alternative: Promise-Kette für ältere Codebasen
function processUserRequestChain(userId, requestData) {
    return getUser(userId)
        .then(user => validateUserOrThrow(user))
        .then(user => checkPermissionsOrThrow(user, requestData.resource))
        .then(([user, resource]) => validateRequestOrThrow(requestData, resource))
        .then(([user, resource]) => processRequest(user, resource, requestData))
        .then(result => logAndReturn(requestData, result));
}

// Hilfsfunktionen, die bei Fehlern werfen
async function validateUserOrThrow(user) {
    const validation = await validateUser(user);
    if (!validation.isValid) {
        throw new Error('Invalid user');
    }
    return user;
}

async function checkPermissionsOrThrow(user, resource) {
    const hasPermission = await checkPermissions(user, resource);
    if (!hasPermission) {
        throw new Error('Permission denied');
    }
    return [user, await getResource(resource)];
}

async function validateRequestOrThrow(requestData, resource) {
    const valid = await validateRequest(requestData, resource);
    if (!valid) {
        throw new Error('Invalid request');
    }
    return [requestData.user, resource];
}

async function logAndReturn(requestData, result) {
    await logActivity(requestData.user, requestData, result);
    return result;
}

CVE-Beispiele

Dieses CWE ist für die direkte CVE-Zuordnung als VERBOTEN markiert, da es ein Codequalitätsproblem und keine direkte Sicherheitslücke darstellt.


Verwandte CWEs

  • CWE-1120: Excessive Code Complexity (übergeordnet)
  • CWE-1121: Excessive McCabe Cyclomatic Complexity (verwandt)
  • CWE-1226: Complexity Issues (Kategoriemitglied)

Referenzen

  1. MITRE Corporation. "CWE-1124: Excessively Deep Nesting." https://cwe.mitre.org/data/definitions/1124.html
  2. "Refactoring" von Martin Fowler – Replace Nested Conditional with Guard Clauses
  3. Code Complete von Steve McConnell – Richtlinien zur Verschachtelungstiefe