Logging übermäßiger Daten

Beschreibung

Logging übermäßiger Daten ist eine Sicherheitsschwachstelle, bei der Software eine übermäßige Menge an Informationen loggt, was Log-Dateien schwer verarbeitbar macht und möglicherweise wichtige Sicherheitsereignisse verdeckt. Obwohl Logging essentiell für Sicherheitsüberwachung und forensische Analyse ist, kann übermäßiges Logging kontraproduktiv sein. Zu viele Log-Daten erzeugen Rauschen, das die Fähigkeit von Administratoren behindert, anomale Bedingungen zu erkennen, bieten Deckung für Angreifer, indem deren Aktivitäten in irrelevanten Einträgen begraben werden, erschweren Debugging und verbrauchen erhebliche Systemressourcen einschließlich Festplattenplatz und CPU-Zeit.

Risiko

Übermäßiges Logging erzeugt mehrere Sicherheits- und Betriebsrisiken. Angreifer können bösartige Aktivitäten in massiven Log-Volumen verstecken, wissend dass Administratoren unwahrscheinlich jeden Eintrag überprüfen. Größe Log-Dateien verbrauchen schnell Festplattenplatz und können potenziell Denial of Service verursachen, wenn Speicher erschöpft ist. Die Verarbeitung übermäßiger Logs verbraucht CPU-Ressourcen und verschlechtert die Systemleistung. Während Sicherheitsvorfällen wird forensische Analyse extrem schwierig, wenn relevante Ereignisse im Rauschen begraben sind.

Lösung

Implementieren Sie geeignete Logging-Levels für jede Umgebung - ausführliches Debug-Logging in der Entwicklung, minimales essentielles Logging in der Produktion. Unterdrücken Sie doppelte Log-Meldungen durch Zusammenfassung wiederholter Einträge (z.B. "letzte Meldung X mal wiederholt"). Konfigurieren Sie maximale Log-Datei-Größen mit Rotation und Archivierung. Implementieren Sie Log-Sampling für High-Volume-Events. Verwenden Sie strukturiertes Logging, um effizientes Filtern zu ermöglichen. Definieren Sie klare Richtlinien, was auf jeder Schweregradestufe geloggt werden sollte und was nicht.

Häufige Auswirkungen

AuswirkungDetails
VerfügbarkeitBereich: Verfügbarkeit

DoS: Ressourcenverbrauch - Übermäßiges Logging verbraucht Festplattenplatz und CPU-Ressourcen und verschlechtert die Systemleistung.
VerantwortlichkeitBereich: Verantwortlichkeit, Nicht-Abstreitbarkeit

Aktivitäten verbergen - Größe Log-Volumen bieten Deckung für Angreifer und verbergen bösartige Aktivitäten im Rauschen.
IntegritätBereich: Integrität

Reduzierter forensischer Wert - Übergroße Logs werden für Sicherheitsanalyse und Incident Response unpraktisch.

Beispielcode

Verwundbarer Code

// Verwundbar: Jede Anfrage im Detail loggen
public class VulnerableRequestHandler {
    private static final Logger logger = Logger.getLogger(VulnerableRequestHandler.class);

    public void handleRequest(HttpServletRequest request) {
        // Verwundbar: Loggt vollständige Anfrage-Details für jede Anfrage
        logger.info("Anfrage empfangen von: " + request.getRemoteAddr());
        logger.info("Anfrage-Methode: " + request.getMethod());
        logger.info("Anfrage-URI: " + request.getRequestURI());
        logger.info("Query-String: " + request.getQueryString());

        // Loggt alle Header
        Enumeration<String> headers = request.getHeaderNames();
        while (headers.hasMoreElements()) {
            String header = headers.nextElement();
            logger.info("Header " + header + ": " + request.getHeader(header));
        }

        // In hochfrequentierten Umgebungen erzeugt dies Gigabytes an Logs
        processRequest(request);
    }
}
# Verwundbar: Logging in engen Schleifen
import logging

logger = logging.getLogger(__name__)

def vulnerable_process_data(large_dataset):
    # Verwundbar: Loggt jedes Element in großem Datensatz
    for i, item in enumerate(large_dataset):
        logger.debug(f"Verarbeite Element {i}: {item}")  # Millionen von Log-Einträgen
        logger.debug(f"Element-Details: {item.get_all_attributes()}")
        logger.debug(f"Element-Metadaten: {item.metadata}")

        result = process_item(item)

        logger.debug(f"Element {i} verarbeitet, Ergebnis: {result}")
        logger.debug(f"Speichernutzung nach Element {i}: {get_memory_usage()}")

    # Für 1 Million Elemente erstellt dies 5+ Millionen Log-Einträge

Gefixter Code

// Gefixt: Angemessenes Logging mit Levels und Zusammenfassung
public class FixedRequestHandler {
    private static final Logger logger = Logger.getLogger(FixedRequestHandler.class);
    private static final AtomicInteger requestCount = new AtomicInteger(0);
    private static final int LOG_SAMPLE_RATE = 100;

    public void handleRequest(HttpServletRequest request) {
        int count = requestCount.incrementAndGet();

        // Gefixt: Nur periodisch Zusammenfassung loggen
        if (count % LOG_SAMPLE_RATE == 0) {
            logger.info("Verarbeitet " + count + " Anfragen");
        }

        // Gefixt: Debug-Level für detaillierte Info (in Produktion deaktiviert)
        if (logger.isDebugEnabled()) {
            logger.debug("Anfrage: " + request.getMethod() + " " + request.getRequestURI());
        }

        try {
            processRequest(request);
        } catch (Exception e) {
            // Gefixt: Nur tatsächliche Fehler mit relevantem Kontext loggen
            logger.error("Anfrage fehlgeschlagen: " + request.getMethod() + " " + request.getRequestURI()
                        + " - " + e.getMessage());
        }
    }
}
# Gefixt: Kontrolliertes Logging mit Sampling und Zusammenfassung
import logging
from collections import Counter

logger = logging.getLogger(__name__)

def fixed_process_data(large_dataset):
    total_items = len(large_dataset)
    processed_count = 0
    error_count = 0
    error_summary = Counter()

    # Gefixt: Start und Ende loggen, nicht jedes Element
    logger.info(f"Starte Verarbeitung von {total_items} Elementen")

    for i, item in enumerate(large_dataset):
        try:
            result = process_item(item)
            processed_count += 1

            # Gefixt: Fortschritts-Logging in Intervallen
            if (i + 1) % 10000 == 0:
                logger.info(f"Fortschritt: {i + 1}/{total_items} Elemente verarbeitet")

        except ProcessingError as e:
            error_count += 1
            error_summary[type(e).__name__] += 1

            # Gefixt: Nur erste Fehler jedes Typs loggen
            if error_summary[type(e).__name__] <= 3:
                logger.warning(f"Verarbeitungsfehler: {e}")

    # Gefixt: Zusammenfassung am Ende
    logger.info(f"Abgeschlossen: {processed_count}/{total_items} erfolgreich, {error_count} Fehler")
    if error_summary:
        logger.warning(f"Fehler-Zusammenfassung: {dict(error_summary)}")
// Gefixt: Minimales Produktions-Logging
const express = require('express');
const app = express();

// Gefixt: Konfigurierbare Logging-Levels
const LOG_LEVEL = process.env.LOG_LEVEL || 'info';

app.use((req, res, next) => {
    const start = Date.now();

    res.on('finish', () => {
        const duration = Date.now() - start;

        // Gefixt: Einzelne Zeile pro Anfrage, nur essentielle Info
        const logData = {
            method: req.method,
            path: req.path,
            status: res.statusCode,
            duration: duration + 'ms'
        };

        // Gefixt: Error-Level für Probleme, Info für normales
        if (res.statusCode >= 500) {
            console.error('Anfragefehler:', JSON.stringify(logData));
        } else if (LOG_LEVEL === 'debug') {
            console.log('Anfrage:', JSON.stringify(logData));
        }
    });

    next();
});

CVE-Beispiele

  • CVE-2007-0421: Server loggte übermäßige Daten beim Empfang fehlerhafter Header und verbrauchte Festplattenplatz.
  • CVE-2002-1154: Anwendung beschränkte Update-Zugriff nicht und erlaubte Angreifern, Fehler-Logs mit übermäßigen Einträgen zu füllen.

Referenzen

  1. MITRE Corporation. "CWE-779: Logging of Excessive Data." https://cwe.mitre.org/data/definitions/779.html
  2. OWASP. "Logging Cheat Sheet." https://cheatsheetseries.owasp.org/cheatsheets/Logging_Cheat_Sheet.html
  3. NIST. "Guide to Computer Security Log Management." SP 800-92.