Funktionsaufruf mit falsch spezifiziertem Argumentwert

Beschreibung

Funktionsaufruf mit falsch spezifiziertem Argumentwert ist ein Programmierfehler, bei dem Code eine Funktion mit einem Argument aufruft, das einen falschen Wert für den beabsichtigten Zweck der Funktion enthält, obwohl der Typ korrekt sein kann. Dies unterscheidet sich von Typunterschieden - das Argument hat den richtigen Typ, aber den falschen Wert. Häufige Beispiele sind das Übergeben von 0 statt 1 für Boolean-Flags, die Verwendung falscher Konstanten, hartcodierte Werte die dynamisch sein sollten, oder invertierte Boolean-Logik. Diese Fehler können dazu führen, dass Funktionen sich gegenteilig zur Absicht des Programmierers verhalten oder kritische Verarbeitung überspringen.

Risiko

Falsche Argumentwerte erzeugen ernsthafte Sicherheitsrisiken, wenn sie sicherheitskritische Funktionen betreffen. Authentifizierungsfunktionen, die mit falschen Flag-Werten aufgerufen werden, melden Fehler möglicherweise nicht korrekt. Autorisierungsprüfungen mit invertierten Boolean-Argumenten gewähren möglicherweise Zugriff, wenn sie ihn verweigern sollten. Fehlerbehandlungsfunktionen, die falsche Fehlercodes erhalten, ergreifen möglicherweise unangemessene Maßnahmen. Das Risiko wird verstärkt, weil diese Bugs oft die Code-Review passieren - der Code sieht syntaktisch korrekt aus und besteht die Typüberprüfung erfolgreich. Sie manifestieren sich typischerweise nur in bestimmten Ausführungspfaden, was ihre Erkennung durch Tests erschwert.

Lösung

Verwenden Sie benannte Konstanten oder Enums statt magischer Zahlen, um die Absicht des Arguments deutlich zu machen. Erstellen Sie Wrapper-Funktionen mit expliziten Namen, die die ausgeführte Operation anzeigen. Verwenden Sie benannte Parameter, wo die Sprache dies unterstützt. Implementieren Sie gründliche Unit-Tests, die das Funktionsverhalten mit verschiedenen Argumentwerten verifizieren. Führen Sie Code-Reviews mit besonderem Fokus auf Argumentwerte in sicherheitskritischen Funktionen durch. Verwenden Sie statische Analysetools, die häufige falsche Wertmuster erkennen können. Erwägen Sie die Verwendung von Builder-Patterns oder Konfigurationsobjekten für Funktionen mit vielen Boolean- oder Flag-Parametern.

Häufige Auswirkungen

AuswirkungDetails
SonstigesBereich: Sonstiges

Qualitätsverschlechterung - Funktionen verhalten sich falsch, wenn sie mit falschen Werten aufgerufen werden, und produzieren unerwartete Ergebnisse.
ZugriffskontrolleBereich: Zugriffskontrolle

Schutzmechanismus umgehen - Sicherheitsfunktionen mit falschen Flag-Werten erzwingen Prüfungen möglicherweise nicht.
IntegritätBereich: Integrität

Unerwarteter Zustand - Systeme geraten in inkonsistente Zustände, wenn Funktionen mit falschen Parametern arbeiten.

Beispielcode

Anfälliger Code

# Anfällig: Falscher Boolean-Wert für Fehlerbehandlungs-Flag
sub ReportAuth {
    my ($username, $result, $die_on_error) = @_;

    if ($result != 0) {
        # Authentifizierung fehlgeschlagen
        if ($die_on_error) {
            die "Authentifizierung fehlgeschlagen für $username";
        }
        # Nur loggen wenn nicht beendet wird
        log_failure($username);
    }
}

# Anfällig: Mit 0 statt 1 aufgerufen
sub authenticate_user {
    my ($username, $password) = @_;

    my $result = check_credentials($username, $password);

    # Anfällig: Sollte 1 sein um bei Fehler zu beenden, aber 0 wird übergeben
    ReportAuth($username, $result, 0);  # FALSCHER WERT!
    # Authentifizierungsfehler werden stillschweigend geloggt, nicht beendet

    return $result == 0;
}
// Anfällig: Falscher Modus-Wert für Dateioperationen
#include <fcntl.h>
#include <sys/stat.h>

void vulnerable_create_file(const char* path) {
    // Anfällig: Falschen Modus verwenden - 0 statt korrekter Berechtigungen
    int fd = open(path, O_CREAT | O_WRONLY, 0);  // Modus 0 = keine Berechtigungen!
    // Datei mit keinen Lese/Schreib/Ausführung-Berechtigungen für niemanden erstellt

    write(fd, "data", 4);
    close(fd);
}

// Anfällig: Falsches Flag für Socket-Optionen
#include <sys/socket.h>

int vulnerable_socket_setup(int sockfd) {
    int optval = 0;  // Sollte 1 sein um Option zu aktivieren

    // Anfällig: optval=0 deaktiviert Option statt sie zu aktivieren
    setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval));
    // SO_REUSEADDR nicht wirklich aktiviert!

    return 0;
}

// Anfällig: Invertierte Boolean-Logik
int vulnerable_is_valid(int error_code) {
    // error_code 0 bedeutet Erfolg, ungleich null bedeutet Fehler

    // Anfällig: Logik ist rückwärts
    return error_code;  // Gibt true (ungleich null) bei FEHLER zurück
    // Sollte sein: return error_code == 0;
}
// Anfällig: Falsche Flag-Werte
public class VulnerableFlags {

    private static final int FLAG_SECURE = 1;
    private static final int FLAG_INSECURE = 0;

    public void processRequest(Request request) {
        // Anfällig: Falsches Flag übergeben
        validateInput(request.getData(), FLAG_INSECURE);  // FALSCH!
        // Sollte FLAG_SECURE sein für sicherheitskritische Validierung
    }

    public void validateInput(String data, int securityLevel) {
        if (securityLevel == FLAG_SECURE) {
            // Gründliche Validierung durchführen
            strictValidation(data);
        } else {
            // Nur minimale Validierung
            basicValidation(data);  // Weniger sicherer Pfad genommen!
        }
    }
}

// Anfällig: Falsche Konstante für Vergleich
public class VulnerableComparison {

    public static final int STATUS_SUCCESS = 0;
    public static final int STATUS_FAILURE = 1;
    public static final int STATUS_PENDING = 2;

    public boolean isOperationSuccessful(int status) {
        // Anfällig: Vergleich mit falscher Konstante
        return status == STATUS_FAILURE;  // FALSCH! Sollte STATUS_SUCCESS sein
        // Gibt true zurück wenn Operation fehlgeschlagen ist!
    }
}
# Anfällig: Falscher Standard- oder hartcodierter Wert
import ssl

def vulnerable_ssl_connection(host, port):
    context = ssl.create_default_context()

    # Anfällig: Falscher Wert deaktiviert Zertifikatsverifizierung
    context.check_hostname = False  # FALSCH! Sollte True sein
    context.verify_mode = ssl.CERT_NONE  # FALSCH! Sollte CERT_REQUIRED sein

    # Verbindung erfolgt ohne Zertifikatsverifizierung
    return context.wrap_socket(socket.socket(), server_hostname=host)

# Anfällig: Falscher Array-Index
def vulnerable_get_permission(permissions, user_type):
    ADMIN_INDEX = 0
    USER_INDEX = 1
    GUEST_INDEX = 2

    # Anfällig: Falschen Index verwenden
    if user_type == 'admin':
        return permissions[USER_INDEX]  # FALSCH! Holt Benutzer-Berechtigungen, nicht Admin
    elif user_type == 'user':
        return permissions[ADMIN_INDEX]  # FALSCH! Holt Admin-Berechtigungen
    return permissions[GUEST_INDEX]

Lösung

# Korrigiert: Benannte Konstanten und klare Parameternamen verwenden
use constant {
    DIE_ON_ERROR => 1,
    LOG_ONLY => 0,
};

sub ReportAuth {
    my ($username, $result, $die_on_error) = @_;

    if ($result != 0) {
        if ($die_on_error) {
            die "Authentifizierung fehlgeschlagen für $username";
        }
        log_failure($username);
    }
}

# Korrigiert: Benannte Konstante für Klarheit verwenden
sub authenticate_user {
    my ($username, $password) = @_;

    my $result = check_credentials($username, $password);

    # Korrigiert: Klare Absicht mit benannter Konstante
    ReportAuth($username, $result, DIE_ON_ERROR);

    return $result == 0;
}

# Alternative: Wrapper-Funktionen verwenden
sub authenticate_or_die {
    my ($username, $password) = @_;
    my $result = check_credentials($username, $password);
    ReportAuth($username, $result, 1);  # Immer bei Fehler beenden
    return $result == 0;
}
// Korrigiert: Korrekte Modus-Werte mit benannten Konstanten verwenden
#include <fcntl.h>
#include <sys/stat.h>

#define SECURE_FILE_MODE (S_IRUSR | S_IWUSR)  // Nur Eigentümer lesen/schreiben

void secure_create_file(const char* path) {
    // Korrigiert: Korrekte Berechtigungen
    int fd = open(path, O_CREAT | O_WRONLY, SECURE_FILE_MODE);
    if (fd < 0) {
        return;  // Fehler behandeln
    }

    write(fd, "data", 4);
    close(fd);
}

// Korrigiert: Korrekter Options-Wert
#include <sys/socket.h>

int secure_socket_setup(int sockfd) {
    int optval = 1;  // Korrigiert: 1 um Option zu aktivieren

    if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR,
                   &optval, sizeof(optval)) < 0) {
        return -1;
    }
    return 0;
}

// Korrigiert: Korrekte Boolean-Logik
int secure_is_valid(int error_code) {
    // Korrigiert: 0 bedeutet Erfolg (gültig), ungleich null bedeutet Fehler (ungültig)
    return error_code == 0;
}

// Alternative: Wrapper mit klarem Namen
int is_success(int result_code) {
    return result_code == 0;
}

int is_error(int result_code) {
    return result_code != 0;
}
// Korrigiert: Enums für typsichere Flags verwenden
public class SecureFlags {

    public enum SecurityLevel {
        INSECURE,
        BASIC,
        SECURE,
        PARANOID
    }

    public void processRequest(Request request) {
        // Korrigiert: Klares, typsicheres Flag
        validateInput(request.getData(), SecurityLevel.SECURE);
    }

    public void validateInput(String data, SecurityLevel level) {
        switch (level) {
            case PARANOID:
            case SECURE:
                strictValidation(data);
                break;
            case BASIC:
                basicValidation(data);
                break;
            case INSECURE:
                // Minimale Validierung
                break;
        }
    }
}

// Korrigiert: Korrekter Konstanten-Vergleich
public class SecureComparison {

    public enum OperationStatus {
        SUCCESS,
        FAILURE,
        PENDING
    }

    public boolean isOperationSuccessful(OperationStatus status) {
        // Korrigiert: Mit SUCCESS vergleichen
        return status == OperationStatus.SUCCESS;
    }
}
# Korrigiert: Korrekte SSL-Konfiguration
import ssl

def secure_ssl_connection(host, port):
    context = ssl.create_default_context()

    # Korrigiert: Sicherheitsfunktionen aktivieren
    context.check_hostname = True
    context.verify_mode = ssl.CERT_REQUIRED

    return context.wrap_socket(socket.socket(), server_hostname=host)

# Korrigiert: Korrekte Array-Indizes mit explizitem Mapping
from enum import IntEnum

class UserType(IntEnum):
    ADMIN = 0
    USER = 1
    GUEST = 2

def secure_get_permission(permissions, user_type: str):
    # Korrigiert: Enum für klares Mapping verwenden
    type_map = {
        'admin': UserType.ADMIN,
        'user': UserType.USER,
        'guest': UserType.GUEST
    }

    index = type_map.get(user_type, UserType.GUEST)
    return permissions[index]

# Alternative: Dictionary für explizites Mapping verwenden
def secure_get_permission_dict(user_type: str):
    permissions = {
        'admin': ['read', 'write', 'delete', 'admin'],
        'user': ['read', 'write'],
        'guest': ['read']
    }
    return permissions.get(user_type, permissions['guest'])

CVE-Beispiele

  • CVE-2008-2121: Falscher Argumentwert in Sicherheitsfunktion erlaubte Umgehung von Zugriffskontrollen.
  • CVE-2006-4243: Falscher Flag-Wert an Authentifizierungsfunktion übergeben, Sicherheit geschwächt.

Referenzen

  1. MITRE Corporation. "CWE-687: Function Call With Incorrectly Specified Argument Value." https://cwe.mitre.org/data/definitions/687.html
  2. CERT C Coding Standard. "DCL00-C. Const-qualify immutable objects."