Übermäßiger Plattform-Ressourcenverbrauch innerhalb einer Schleife

Beschreibung

Übermäßiger Plattform-Ressourcenverbrauch innerhalb einer Schleife tritt auf, wenn Software einen Schleifenkörper oder eine Schleifenbedingung enthält, die direkt oder indirekt Plattformressourcen wie Messaging-Verbindungen, Sitzungen, Sperren, Dateideskriptoren, Datenbankverbindungen oder Netzwerk-Sockets verbraucht. Wenn diese Ressourcenerfassungen innerhalb von Schleifen ohne ordnungsgemäße Freigabe erfolgen, akkumulieren sich die Ressourcen mit jeder Iteration. Wenn Angreifer die Anzahl der Schleifeniterationen kontrollieren oder beeinflussen können, können sie Systemressourcen erschöpfen, was zu Denial-of-Service-Bedingungen führt.

Risiko

Diese Schwachstelle kann zu schwerwiegenden Verfügbarkeitsproblemen führen. Ressourcenerschöpfung durch schleifenbasierte Akkumulation kann Anwendungen zum Absturz bringen, die Systemleistung verschlechtern oder Dienste unverfügbar machen. Dateideskriptor-Erschöpfung verhindert neue Verbindungen. Datenbankverbindungspool-Erschöpfung blockiert alle Datenbankoperationen. Sperrenakkumulation verursacht Deadlocks. Das Risiko wird verstärkt, wenn: (1) Schleifeniterationen durch externe Eingaben kontrolliert werden, (2) Ressourcen beim Schleifenausgang nicht ordnungsgemäß freigegeben werden, oder (3) Ausnahmebehandlung erworbene Ressourcen nicht bereinigt. Angreifer können dies für gezielte Denial-of-Service-Angriffe ausnutzen.

Lösung

Geben Sie Ressourcen innerhalb derselben Schleifeniteration frei, in der sie erworben wurden. Verwenden Sie try-finally- oder try-with-resources-Muster, um Bereinigung bei Ausnahmen sicherzustellen. Vermeiden Sie das Erwerben von Ressourcen innerhalb von Schleifen, wenn möglich - erwerben Sie einmal vor der Schleife und verwenden Sie sie wieder. Implementieren Sie Ressourcenpooling mit Größenbegrenzungen. Setzen Sie Timeouts für Ressourcenerfassung. Validieren Sie Schleifengrenzen gegen externe Eingaben. Überwachen Sie den Ressourcenverbrauch und implementieren Sie Circuit Breaker. Verwenden Sie statische Analysetools, um Ressourcenlecks in Schleifen zu erkennen. Implementieren Sie Ratenbegrenzung für Operationen, die ressourcenintensive Schleifen auslösen.

Häufige Auswirkungen

AuswirkungDetails
VerfügbarkeitBereich: Verfügbarkeit

DoS: Ressourcenverbrauch - Schleifenbasierte Ressourcenakkumulation kann Dateideskriptoren, Verbindungen, Speicher oder andere Plattformressourcen erschöpfen.
VerfügbarkeitBereich: Verfügbarkeit

DoS: Absturz/Beenden/Neustart - Ressourcenerschöpfung kann Anwendungsabstürze verursachen oder Neustarts erzwingen.
AndereBereich: Ändere

Leistungsreduktion - Selbst ohne vollständige Erschöpfung verschlechtert übermäßiger Ressourcenverbrauch die Gesamtsystemleistung.

Beispielcode

Anfälliger Code

// Anfällig: Öffnen von Datei-Handles in Schleife ohne Schließen
public class VulnerableFileProcessor {

    public void processFiles(List<String> filePaths) {
        for (String path : filePaths) {
            // Anfällig: FileInputStream geöffnet aber nie geschlossen
            FileInputStream fis = new FileInputStream(path);
            byte[] data = fis.readAllBytes();
            processData(data);
            // fis wird nie geschlossen - Datei-Handles akkumulieren!
        }
        // Nach Verarbeitung von 1000+ Dateien gehen System die Dateideskriptoren aus
    }
}
// Anfällig: Datenbankverbindungen in Schleife erworben
public class VulnerableDatabaseProcessor {

    public List<Result> processIds(List<Integer> ids) {
        List<Result> results = new ArrayList<>();

        for (Integer id : ids) {
            // Anfällig: Neue Verbindung pro Iteration
            Connection conn = dataSource.getConnection();
            PreparedStatement stmt = conn.prepareStatement("SELECT * FROM data WHERE id = ?");
            stmt.setInt(1, id);
            ResultSet rs = stmt.executeQuery();

            if (rs.next()) {
                results.add(mapResult(rs));
            }
            // Verbindung nie geschlossen!
            // Verbindungspool erschöpft nach ~100 Iterationen
        }

        return results;
    }
}
# Anfällig: Netzwerkverbindungen in Schleife
import socket

def vulnerable_check_servers(hosts):
    results = []

    for host in hosts:
        # Anfällig: Socket erstellt aber nie geschlossen
        sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        sock.settimeout(5)

        try:
            sock.connect((host, 80))
            results.append((host, "erreichbar"))
        except:
            results.append((host, "nicht erreichbar"))
        # Socket nie geschlossen - Dateideskriptoren lecken

    return results

# Nach Prüfung von ~1000 Hosts gehen Prozess die Dateideskriptoren aus
// Anfällig: Erwerben von Sperren in Schleife ohne Freigabe
public class VulnerableLockManager
{
    private Dictionary<string, object> locks = new Dictionary<string, object>();

    public void ProcessItems(List<Item> items)
    {
        foreach (var item in items)
        {
            // Anfällig: Sperre erworben aber nie freigegeben
            var lockObj = GetOrCreateLock(item.Category);
            Monitor.Enter(lockObj);

            try
            {
                ProcessItem(item);
            }
            catch (Exception ex)
            {
                // Ausnahme gibt Sperre nicht frei!
                Log(ex);
            }
            // Monitor.Exit nie aufgerufen - Deadlock droht
        }
    }
}

Korrigierter Code

// Korrigiert: Ordnungsgemäße Ressourcenverwaltung in Schleife
public class FixedFileProcessor {

    public void processFiles(List<String> filePaths) {
        for (String path : filePaths) {
            // Korrigiert: try-with-resources stellt Schließung sicher
            try (FileInputStream fis = new FileInputStream(path)) {
                byte[] data = fis.readAllBytes();
                processData(data);
            } catch (IOException e) {
                log.error("Verarbeitung fehlgeschlagen: " + path, e);
                // Ressource trotzdem bei Ausnahme geschlossen
            }
        }
    }
}
// Korrigiert: Einzelne Verbindung für Schleife oder ordnungsgemäße Verbindungsverwaltung
public class FixedDatabaseProcessor {

    // Option 1: Einzelne Verbindung für gesamte Schleife
    public List<Result> processIdsEfficient(List<Integer> ids) {
        List<Result> results = new ArrayList<>();

        try (Connection conn = dataSource.getConnection();
             PreparedStatement stmt = conn.prepareStatement(
                 "SELECT * FROM data WHERE id = ?")) {

            for (Integer id : ids) {
                stmt.setInt(1, id);
                try (ResultSet rs = stmt.executeQuery()) {
                    if (rs.next()) {
                        results.add(mapResult(rs));
                    }
                }
                stmt.clearParameters();
            }
        }

        return results;
    }

    // Option 2: Batch-Abfrage um Schleife ganz zu vermeiden
    public List<Result> processIdsBatch(List<Integer> ids) {
        if (ids.isEmpty()) return Collections.emptyList();

        String placeholders = String.join(",",
            Collections.nCopies(ids.size(), "?"));

        String sql = "SELECT * FROM data WHERE id IN (" + placeholders + ")";

        try (Connection conn = dataSource.getConnection();
             PreparedStatement stmt = conn.prepareStatement(sql)) {

            for (int i = 0; i < ids.size(); i++) {
                stmt.setInt(i + 1, ids.get(i));
            }

            try (ResultSet rs = stmt.executeQuery()) {
                List<Result> results = new ArrayList<>();
                while (rs.next()) {
                    results.add(mapResult(rs));
                }
                return results;
            }
        }
    }
}
# Korrigiert: Ordnungsgemäße Socket-Verwaltung
import socket
from contextlib import contextmanager

@contextmanager
def managed_socket(timeout=5):
    """Context-Manager für Socket-Bereinigung"""
    sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    sock.settimeout(timeout)
    try:
        yield sock
    finally:
        sock.close()


def fixed_check_servers(hosts):
    results = []

    for host in hosts:
        # Korrigiert: Socket ordnungsgemäß via Context-Manager geschlossen
        with managed_socket() as sock:
            try:
                sock.connect((host, 80))
                results.append((host, "erreichbar"))
            except (socket.timeout, socket.error):
                results.append((host, "nicht erreichbar"))

    return results
// Korrigiert: Ordnungsgemäße Sperrenverwaltung mit try-finally
public class FixedLockManager
{
    private readonly ConcurrentDictionary<string, object> locks =
        new ConcurrentDictionary<string, object>();

    public void ProcessItems(List<Item> items)
    {
        foreach (var item in items)
        {
            var lockObj = locks.GetOrAdd(item.Category, _ => new object());
            bool lockTaken = false;

            try
            {
                // Korrigiert: Sperrenerfassung verfolgen
                Monitor.Enter(lockObj, ref lockTaken);
                ProcessItem(item);
            }
            finally
            {
                // Korrigiert: Sperre immer freigeben wenn erworben
                if (lockTaken)
                {
                    Monitor.Exit(lockObj);
                }
            }
        }
    }

    // Besser: lock-Anweisung verwenden
    public void ProcessItemsSimple(List<Item> items)
    {
        foreach (var item in items)
        {
            var lockObj = locks.GetOrAdd(item.Category, _ => new object());

            // Korrigiert: lock-Anweisung behandelt Freigabe automatisch
            lock (lockObj)
            {
                ProcessItem(item);
            }
        }
    }
}

CVE-Beispiele

Diese CWE beschreibt ein Muster, das zu Denial-of-Service-Schwachstellen beitragen kann. Ressourcenerschöpfung durch unsachgemäße Schleifenbehandlung war ein Faktor bei verschiedenen Verfügbarkeitsvorfällen.


Verwandte CWEs

  • CWE-405: Asymmetric Resource Consumption (Amplification) (Eltern)
  • CWE-400: Uncontrolled Resource Consumption (verwandt)
  • CWE-404: Improper Resource Shutdown or Release (verwandt)
  • CWE-1006: Bad Coding Practices (Kategoriemitglied)

Referenzen

  1. MITRE Corporation. "CWE-1050: Excessive Platform Resource Consumption within a Loop." https://cwe.mitre.org/data/definitions/1050.html

  2. CISQ. "Automated Source Code Quality Measures."

  3. Oracle. "Java try-with-resources Statement."