Unsachgemäße Validierung einer angegebenen Menge in der Eingabe

Beschreibung

Unsachgemäße Validierung einer angegebenen Menge in der Eingabe tritt auf, wenn ein Produkt eine Eingabe erhält, die eine Menge spezifiziert (Größe, Länge, Häufigkeit, Preis, Rate, Anzahl der Operationen, Zeit usw.), aber die Menge nicht validiert oder falsch validiert, ob sie die erforderlichen Eigenschaften hat. Mengen werden häufig verwendet, um Ressourcen zuzuweisen, Berechnungen durchzuführen und Iterationen zu steuern. Code hängt oft von der ordnungsgemäßen Validierung dieser Eingaben für einen sicheren Betrieb ab. Ohne ordnungsgemäße Validierung können Angreifer Ressourcenerschöpfung, Buffer Overflows, Integer Overflows oder Verstöße gegen die Geschäftslogik verursachen.

Risiko

Unsachgemäße Mengenvalidierung hat schwerwiegende Sicherheitsauswirkungen. Buffer Overflows können auftreten. Integer-Overflow-Angriffe sind möglich. Speichererschöpfung kann eintreten. Ressourcenverbrauchsangriffe werden ermöglicht. Geschäftslogik kann missbraucht werden. Endlosschleifen können ausgelöst werden. Finanzberechnungen können manipuliert werden. Systemverfügbarkeit kann beeinträchtigt werden.

Lösung

Implementieren Sie eine Validierung nach dem Prinzip "bekannt Gutes akzeptieren" unter Verwendung strikter Allowlists. Validieren Sie alle relevanten Eigenschaften einschließlich Länge, Typ, zulässiger Bereiche und Syntax. Prüfen Sie die Konformität mit der Geschäftslogik. Verlassen Sie sich nicht allein auf die Erkennung bösartiger Eingaben. Validieren Sie sowohl Mindest- als auch Maximalwerte. Berücksichtigen Sie Probleme mit vorzeichenbehafteten vs. vorzeichenlosen Werten. Implementieren Sie Bereichsprüfungen vor der Verwendung von Mengen.

Häufige Auswirkungen

AuswirkungDetails
VerfügbarkeitBereich: Verfügbarkeit

DoS - Übermäßiger Ressourcenverbrauch oder Endlosschleifen.
IntegritätBereich: Integrität

Speicher modifizieren - Buffer Overflows durch ungültige Größen.
SonstigesBereich: Sonstiges

Verstöße gegen die Geschäftslogik durch ungültige Mengen.

Beispielcode und Lösung

Verwundbarer Code

// VERWUNDBAR: Keine Validierung von Mengeneingaben

#include <stdint.h>
#include <stdlib.h>
#include <string.h>

// VERWUNDBAR: Keine Validierung des Größenparameters
void* vulnerable_allocate(size_t size) {
    // VERWUNDBAR: Keine Prüfung auf übermäßige Größe
    // Angreifer kann riesige Allokation anfordern

    void* buffer = malloc(size);  // Könnte Speicher erschöpfen
    return buffer;
}

// VERWUNDBAR: Keine Validierung der Anzahl
void vulnerable_process_items(int count) {
    // VERWUNDBAR: Keine Obergrenze geprüft
    // VERWUNDBAR: Keine Negativprüfung

    for (int i = 0; i < count; i++) {
        // Wenn count sehr groß ist, läuft es endlos
        // Wenn count negativ ist (bei unsigniertem Vergleich), unerwartetes Verhalten
        process_item(i);
    }
}

// VERWUNDBAR: Integer-Overflow bei Größenberechnung
void vulnerable_copy_data(const uint8_t* src, size_t element_size,
                          size_t element_count) {
    // VERWUNDBAR: Multiplikation kann überlaufen
    size_t total_size = element_size * element_count;

    // Wenn element_size=0x10000 und element_count=0x10000:
    // total_size = 0x100000000 = 0 (32-Bit-Overflow)

    uint8_t* buffer = malloc(total_size);  // Allokiert 0 oder kleinen Puffer
    memcpy(buffer, src, total_size);       // Verwendet aber die übergelaufene Größe?

    // Tatsächlich verwendet memcpy auch total_size, aber wenn wir hätten:
    // memcpy(buffer, src, element_size * element_count);
    // Die Kopie würde überlaufen
}

// VERWUNDBAR: Negative Menge im E-Commerce
struct order {
    int item_id;
    int quantity;
    double price;
};

double vulnerable_calculate_total(struct order* orders, int num_orders) {
    double total = 0;

    for (int i = 0; i < num_orders; i++) {
        // VERWUNDBAR: Keine Validierung der Menge
        total += orders[i].quantity * orders[i].price;

        // Wenn Menge negativ ist, verringert sich der Gesamtbetrag!
        // Angreifer bestellt -100 Artikel und erhält Geld zurück
    }

    return total;
}

// VERWUNDBAR: Array-Index aus Menge
void vulnerable_array_access(uint8_t* data, int offset, int length) {
    // VERWUNDBAR: Keine Grenzprüfung

    for (int i = 0; i < length; i++) {
        // Wenn offset oder length negativ oder zu groß ist, Zugriff außerhalb der Grenzen
        process_byte(data[offset + i]);
    }
}
// VERWUNDBAR: Java mit unvalidierten Mengen

public class VulnerableShoppingCart {

    // VERWUNDBAR: Keine Mengenvalidierung
    public double calculateTotal(List<OrderItem> items) {
        double total = 0;

        for (OrderItem item : items) {
            // VERWUNDBAR: Menge nicht validiert
            // Negative Mengen schreiben dem Kunden gut!
            total += item.getQuantity() * item.getPrice();
        }

        return total;
    }

    // VERWUNDBAR: Keine Validierung der angeforderten Array-Größe
    public byte[] createBuffer(int requestedSize) {
        // VERWUNDBAR: Keine Obergrenze geprüft
        // OutOfMemoryError möglich

        return new byte[requestedSize];
    }

    // VERWUNDBAR: Schleifenanzahl aus Benutzereingabe
    public void processRequests(int count) {
        // VERWUNDBAR: Keine Validierung der Anzahl
        // Könnte negativ oder extrem groß sein

        for (int i = 0; i < count; i++) {
            processRequest(i);  // DoS wenn count riesig ist
        }
    }
}
# VERWUNDBAR: Python mit unvalidierten Mengen

def vulnerable_allocate_list(size):
    # VERWUNDBAR: Keine Validierung der Größe
    # Kann Speicher erschöpfen

    return [None] * size  # Erstellt Liste mit 'size' Elementen

def vulnerable_repeat_operation(count):
    # VERWUNDBAR: Keine Validierung der Anzahl

    for i in range(count):
        # Wenn count in Python 2 negativ ist, gibt range() leer zurück
        # Wenn count riesig ist, läuft es sehr lange
        do_operation(i)

def vulnerable_calculate_price(quantity, unit_price):
    # VERWUNDBAR: Keine Validierung der Menge
    # Negative Menge = negativer Gesamtbetrag = Rückerstattung!

    return quantity * unit_price

def vulnerable_slice_data(data, offset, length):
    # VERWUNDBAR: Keine Grenzvalidierung

    return data[offset:offset + length]
    # Wenn offset negativ ist, wird vom Ende geschnitten
    # Wenn length negativ ist, unerwartete Ergebnisse

Sichere Lösung

// SICHER: Ordnungsgemäße Validierung von Mengeneingaben

#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
#include <limits.h>

// SICHER: Größenparameter validieren
void* secure_allocate(size_t size, size_t max_allowed) {
    // SICHER: Gegen Maximum prüfen
    if (size == 0) {
        return NULL;  // Ungültige Anfrage
    }

    if (size > max_allowed) {
        log_error("Allokationsgröße %zu überschreitet Maximum %zu", size, max_allowed);
        return NULL;
    }

    void* buffer = malloc(size);
    if (buffer == NULL) {
        log_error("Allokation fehlgeschlagen für Größe %zu", size);
    }

    return buffer;
}

// SICHER: Anzahl mit Grenzen validieren
bool secure_process_items(int count, int max_count) {
    // SICHER: Bereich validieren
    if (count < 0) {
        log_error("Negative Anzahl: %d", count);
        return false;
    }

    if (count > max_count) {
        log_error("Anzahl %d überschreitet Maximum %d", count, max_count);
        return false;
    }

    for (int i = 0; i < count; i++) {
        if (!process_item(i)) {
            return false;
        }
    }

    return true;
}

// SICHER: Integer-Overflow bei Größenberechnung erkennen
bool secure_copy_data(const uint8_t* src, size_t src_size,
                      size_t element_size, size_t element_count,
                      uint8_t** out_buffer, size_t* out_size) {
    // SICHER: Auf Multiplikationsüberlauf prüfen
    if (element_count != 0 && element_size > SIZE_MAX / element_count) {
        log_error("Größenüberlauf: %zu * %zu", element_size, element_count);
        return false;
    }

    size_t total_size = element_size * element_count;

    // SICHER: Gegen Quellgröße validieren
    if (total_size > src_size) {
        log_error("Angeforderte Größe %zu überschreitet Quelle %zu", total_size, src_size);
        return false;
    }

    uint8_t* buffer = secure_allocate(total_size, MAX_BUFFER_SIZE);
    if (buffer == NULL) {
        return false;
    }

    memcpy(buffer, src, total_size);

    *out_buffer = buffer;
    *out_size = total_size;
    return true;
}

// SICHER: Menge im E-Commerce validieren
typedef struct {
    int item_id;
    int quantity;
    double price;
} order_item_t;

bool secure_calculate_total(const order_item_t* orders, int num_orders,
                            double* total_out) {
    if (orders == NULL || total_out == NULL) {
        return false;
    }

    // SICHER: num_orders validieren
    if (num_orders < 0 || num_orders > MAX_ORDER_ITEMS) {
        log_error("Ungültige Anzahl von Bestellungen: %d", num_orders);
        return false;
    }

    double total = 0;

    for (int i = 0; i < num_orders; i++) {
        // SICHER: Menge muss positiv sein
        if (orders[i].quantity <= 0) {
            log_error("Ungültige Menge %d für Artikel %d",
                     orders[i].quantity, orders[i].item_id);
            return false;
        }

        // SICHER: Menge muss angemessen sein
        if (orders[i].quantity > MAX_ITEM_QUANTITY) {
            log_error("Menge %d überschreitet Maximum für Artikel %d",
                     orders[i].quantity, orders[i].item_id);
            return false;
        }

        // SICHER: Preis muss positiv sein
        if (orders[i].price <= 0) {
            log_error("Ungültiger Preis für Artikel %d", orders[i].item_id);
            return false;
        }

        total += orders[i].quantity * orders[i].price;
    }

    *total_out = total;
    return true;
}

// SICHER: Sicherer Array-Zugriff mit Grenzprüfung
bool secure_process_range(const uint8_t* data, size_t data_size,
                          size_t offset, size_t length) {
    // SICHER: Offset validieren
    if (offset >= data_size) {
        log_error("Offset %zu außerhalb der Grenzen (Größe=%zu)", offset, data_size);
        return false;
    }

    // SICHER: Länge validieren
    if (length == 0) {
        return true;  // Nichts zu verarbeiten
    }

    // SICHER: offset + length auf Überlauf prüfen
    if (length > data_size - offset) {
        log_error("Länge %zu überschreitet verbleibende Daten bei Offset %zu",
                 length, offset);
        return false;
    }

    for (size_t i = 0; i < length; i++) {
        process_byte(data[offset + i]);
    }

    return true;
}
// SICHER: Java mit validierten Mengen

public class SecureShoppingCart {

    private static final int MAX_QUANTITY = 10000;
    private static final int MAX_BUFFER_SIZE = 10 * 1024 * 1024;  // 10 MB
    private static final int MAX_ITERATIONS = 1000000;

    // SICHER: Menge validieren
    public double calculateTotal(List<OrderItem> items) throws ValidationException {
        double total = 0;

        for (OrderItem item : items) {
            int quantity = item.getQuantity();

            // SICHER: Menge validieren
            if (quantity <= 0) {
                throw new ValidationException(
                    "Ungültige Menge: " + quantity + " für Artikel " + item.getId());
            }

            if (quantity > MAX_QUANTITY) {
                throw new ValidationException(
                    "Menge " + quantity + " überschreitet Maximum " + MAX_QUANTITY);
            }

            double price = item.getPrice();

            // SICHER: Preis validieren
            if (price <= 0) {
                throw new ValidationException(
                    "Ungültiger Preis für Artikel " + item.getId());
            }

            total += quantity * price;
        }

        return total;
    }

    // SICHER: Puffergröße validieren
    public byte[] createBuffer(int requestedSize) throws ValidationException {
        // SICHER: Bereich validieren
        if (requestedSize <= 0) {
            throw new ValidationException("Ungültige Puffergröße: " + requestedSize);
        }

        if (requestedSize > MAX_BUFFER_SIZE) {
            throw new ValidationException(
                "Puffergröße " + requestedSize + " überschreitet Maximum " + MAX_BUFFER_SIZE);
        }

        return new byte[requestedSize];
    }

    // SICHER: Schleifenanzahl validieren
    public void processRequests(int count) throws ValidationException {
        // SICHER: Anzahl validieren
        if (count < 0) {
            throw new ValidationException("Negative Anzahl: " + count);
        }

        if (count > MAX_ITERATIONS) {
            throw new ValidationException(
                "Anzahl " + count + " überschreitet Maximum " + MAX_ITERATIONS);
        }

        for (int i = 0; i < count; i++) {
            processRequest(i);
        }
    }
}
# SICHER: Python mit validierten Mengen

MAX_LIST_SIZE = 10000000
MAX_ITERATIONS = 1000000
MAX_QUANTITY = 10000

def secure_allocate_list(size):
    # SICHER: Größe validieren
    if not isinstance(size, int):
        raise TypeError(f"Größe muss Integer sein, erhalten {type(size)}")

    if size < 0:
        raise ValueError(f"Größe darf nicht negativ sein: {size}")

    if size > MAX_LIST_SIZE:
        raise ValueError(f"Größe {size} überschreitet Maximum {MAX_LIST_SIZE}")

    return [None] * size

def secure_repeat_operation(count):
    # SICHER: Anzahl validieren
    if not isinstance(count, int):
        raise TypeError(f"Anzahl muss Integer sein, erhalten {type(count)}")

    if count < 0:
        raise ValueError(f"Anzahl darf nicht negativ sein: {count}")

    if count > MAX_ITERATIONS:
        raise ValueError(f"Anzahl {count} überschreitet Maximum {MAX_ITERATIONS}")

    for i in range(count):
        do_operation(i)

def secure_calculate_price(quantity, unit_price):
    # SICHER: Menge validieren
    if not isinstance(quantity, (int, float)):
        raise TypeError(f"Menge muss numerisch sein, erhalten {type(quantity)}")

    if quantity <= 0:
        raise ValueError(f"Menge muss positiv sein: {quantity}")

    if quantity > MAX_QUANTITY:
        raise ValueError(f"Menge {quantity} überschreitet Maximum {MAX_QUANTITY}")

    # SICHER: Preis validieren
    if not isinstance(unit_price, (int, float)):
        raise TypeError(f"Preis muss numerisch sein, erhalten {type(unit_price)}")

    if unit_price <= 0:
        raise ValueError(f"Preis muss positiv sein: {unit_price}")

    return quantity * unit_price

def secure_slice_data(data, offset, length):
    # SICHER: Parameter validieren
    if not isinstance(offset, int) or not isinstance(length, int):
        raise TypeError("Offset und Länge müssen Integer sein")

    if offset < 0:
        raise ValueError(f"Offset darf nicht negativ sein: {offset}")

    if length < 0:
        raise ValueError(f"Länge darf nicht negativ sein: {length}")

    if offset >= len(data):
        raise ValueError(f"Offset {offset} außerhalb der Grenzen (Größe={len(data)})")

    if offset + length > len(data):
        raise ValueError(f"Offset {offset} + Länge {length} überschreitet Datengröße")

    return data[offset:offset + length]

CVE-Beispiele

  • CVE-2025-46687: Fehlende Längenprüfung führte zu Integer-Overflow und Heap-Buffer-Overflow.
  • CVE-2019-19911: Unvalidierte Bildband-Spezifikationen verursachten Speichererschöpfung.
  • CVE-2008-1440: Fehlende Validierung des Längenfeldes verursachte Endlosschleifen.
  • CVE-2008-2374: Lücken bei der Validierung der Zeichenkettenlänge ermöglichten Speicherangriffe.

Verwandte CWEs

  • CWE-20: Unsachgemäße Eingabevalidierung (übergeordnet)
  • CWE-606: Ungeprüfte Eingabe für Schleifenbedingung (untergeordnet)
  • CWE-789: Speicherallokation mit übermäßigem Größenwert (kann vorausgehen)
  • CWE-190: Integer-Overflow oder Wraparound (verwandt)

Referenzen

  1. MITRE Corporation. "CWE-1284: Improper Validation of Specified Quantity in Input." https://cwe.mitre.org/data/definitions/1284.html
  2. OWASP. "Input Validation Cheat Sheet"
  3. CERT. "Secure Coding Standards"