Funktionsaufruf mit falscher Variable oder Referenz als Argument

Beschreibung

Funktionsaufruf mit falscher Variable oder Referenz als Argument ist ein Programmierfehler, bei dem Code eine Funktion mit der falschen Variable oder Referenz als Argument aufruft. Im Gegensatz zu Typ- oder Wertfehlern tritt dies auf, wenn ein Programmierer versehentlich eine andere Variable als beabsichtigt übergibt - oft durch Tippfehler, Copy-Paste-Fehler oder Verwechslung zwischen ähnlich benannten Variablen. Die übergebene Variable kann den korrekten Typ und sogar einen vernünftigen Wert haben, aber es ist einfach nicht die Variable, mit der die Funktion arbeiten sollte. Dies kann dazu führen, dass Funktionen die falschen Daten verarbeiten, mit ernsthaften Sicherheitsauswirkungen.

Risiko

Das Übergeben der falschen Variable an Funktionen erzeugt ernsthafte Sicherheitsrisiken, die schwer zu erkennen sind. Autorisierungsprüfungen, die falsche Rollen-Arrays verwenden, gewähren möglicherweise unangemessenen Zugriff. Sicherheitsfunktionen, die auf falschen Datenstrukturen arbeiten, liefern möglicherweise falsche Validierung. Speicheroperationen auf falschen Puffern können Korruption oder Informationslecks verursachen. Das Risiko wird verstärkt, weil diese Bugs oft syntaktisch und typkorrekt erscheinen und Compiler-Prüfungen sowie oberflächliche Code-Reviews passieren. In Sicherheitskontexten kann die Verwendung der falschen Variable - wie das Übergeben von Admin-Rollen statt Benutzerrollen - Zugangskontrollsysteme vollständig untergraben.

Lösung

Verwenden Sie aussagekräftige und unterscheidbare Variablennamen, die den Zweck klar anzeigen. Vermeiden Sie es, Variablen ähnlich wie globale oder statische Variablen zu benennen. Minimieren Sie den Variablenbereich, um die Chance zu reduzieren, falsche Variablen zu verwenden. Verwenden Sie IDE-Funktionen, die die Variablenverwendung hervorheben. Führen Sie sorgfältige Code-Reviews durch, die speziell nach Copy-Paste-Fehlern und Variablennamenverwechslungen suchen. Implementieren Sie umfassende Unit-Tests, die verifizieren, dass Funktionen auf den beabsichtigten Daten arbeiten. Verwenden Sie statische Analysetools, die verdächtige Variablenverwendungsmuster erkennen können. Erwägen Sie die Verwendung benannter Parameter, wo die Sprache dies unterstützt.

Häufige Auswirkungen

AuswirkungDetails
SonstigesBereich: Sonstiges

Qualitätsverschlechterung - Funktionen arbeiten auf falschen Daten und produzieren falsche und unvorhersehbare Ergebnisse.
ZugriffskontrolleBereich: Zugriffskontrolle

Privilegien erlangen oder Identität annehmen - Die Verwendung falscher Rollen- oder Berechtigungsvariablen kann unbefugten Zugriff gewähren.
VertraulichkeitBereich: Vertraulichkeit

Anwendungsdaten lesen - Die Verarbeitung falscher Puffer oder Datenstrukturen kann sensible Informationen preisgeben.

Beispielcode

Anfälliger Code

// Anfällig: Statische Admin-Rollen statt der tatsächlichen Benutzerrollen verwenden
public class VulnerableAccessControl {

    // Statisches Admin-Rollen-Array als Referenz
    private static final String[] ADMIN_ROLES = {"admin", "superuser", "root"};

    public boolean checkAccess(String resource, String[] userRoles) {
        // Anfällig: Versehentlich ADMIN_ROLES statt userRoles verwenden!
        return accessGranted(resource, ADMIN_ROLES);  // FALSCHE VARIABLE!
        // Jeder Benutzer erhält Admin-Level Zugriffsprüfung
        // Sollte sein: return accessGranted(resource, userRoles);
    }

    private boolean accessGranted(String resource, String[] roles) {
        for (String role : roles) {
            if (hasPermission(role, resource)) {
                return true;
            }
        }
        return false;
    }
}

// Anfällig: Copy-Paste-Fehler mit ähnlichen Variablennamen
public class VulnerableCopyPaste {

    public void processUserData(User sourceUser, User targetUser) {
        // Berechtigungen des Quellbenutzers validieren
        validatePermissions(sourceUser);

        // Anfällig: Copy-Paste-Fehler - sourceUser zweimal verwenden
        copyData(sourceUser, sourceUser);  // FALSCH! Sollte targetUser sein
        // Daten von Quelle zu sich selbst kopiert statt zum Ziel
    }

    public void updateRecords(Record oldRecord, Record newRecord) {
        // Anfällig: Variablen vertauscht
        database.delete(newRecord);  // FALSCH! Löscht neu statt alt
        database.insert(oldRecord);  // FALSCH! Fügt alt wieder ein statt neu
    }
}
// Anfällig: Falscher Puffer in Kernel-Code verwendet (CVE-2005-2548 Muster)
#include <string.h>

struct packet_header {
    int type;
    int length;
    char data[256];
};

struct packet_header global_header;  // Globale Vorlage

// Anfällig: Falsche Variable im ersten Argument
void vulnerable_init_packet(struct packet_header* user_packet) {
    // Anfällig: global_header als Ziel statt user_packet verwenden
    memcpy(&global_header, &global_header, sizeof(struct packet_header));
    // Kopiert global zu sich selbst - user_packet unverändert!
    // Sollte sein: memcpy(user_packet, &global_header, sizeof(...))
}

// Anfällig: Falscher Pointer verursacht NULL-Dereferenzierung
void vulnerable_process(struct data* input, struct data* output) {
    struct data* temp = NULL;

    if (validate(input)) {
        temp = allocate_data();
        // ... Verarbeitung ...
    }

    // Anfällig: 'input' verwendet wo 'temp' beabsichtigt war
    if (input != NULL) {  // Sollte 'temp' prüfen
        copy_data(output, input);  // Verwendet möglicherweise unvalidiertes temp
    }
}
# Anfällig: Falsche Liste in Schleife verwenden
def vulnerable_batch_process(pending_items, completed_items):
    processed = []

    # Anfällig: Über completed_items iterieren statt pending_items
    for item in completed_items:  # FALSCHE LISTE!
        result = process(item)
        processed.append(result)

    # Verarbeitet bereits abgeschlossene Elemente erneut, verpasst ausstehende
    return processed

# Anfällig: Falsches Dictionary im Sicherheitskontext
class VulnerableAuth:

    def __init__(self):
        self.valid_tokens = {}  # Benutzer-Tokens
        self.revoked_tokens = {}  # Ungültig gemachte Tokens

    def validate_token(self, token):
        # Anfällig: Falsches Dictionary prüfen
        if token in self.revoked_tokens:  # FALSCH! Sollte valid_tokens prüfen
            return True  # Akzeptiert widerrufene Tokens!
        return False

# Anfällig: Ähnliche Variablennamen
def calculate_discount(base_price, discount_rate, discounted_price):
    # Anfällig: discounted_price statt base_price verwenden
    calculated = discounted_price * (1 - discount_rate)  # FALSCH!
    # Wendet Rabatt auf bereits rabattierten Preis an
    # Sollte base_price verwenden
    return calculated
// Anfällig: Falsche Objekteigenschaft verwenden
function vulnerableUserUpdate(currentUser, newData) {
    const adminDefaults = {
        role: 'admin',
        permissions: ['all']
    };

    const userDefaults = {
        role: 'user',
        permissions: ['read']
    };

    // Anfällig: adminDefaults statt userDefaults verwenden
    return Object.assign({}, adminDefaults, newData);  // FALSCH!
    // Normale Benutzer erhalten Admin-Standardwerte
}

// Anfällig: Falsches Array in splice
function vulnerableRemoveItem(activeList, archiveList, itemId) {
    const index = activeList.findIndex(item => item.id === itemId);

    if (index !== -1) {
        // Anfällig: Aus archiveList entfernen statt activeList
        archiveList.splice(index, 1);  // FALSCHES ARRAY!
        // Entfernt falsches Element aus falscher Liste
    }
}

Lösung

// Korrigiert: Korrekte Variablen mit klarer Benennung verwenden
public class SecureAccessControl {

    private static final String[] ADMIN_ROLES = {"admin", "superuser", "root"};

    public boolean checkAccess(String resource, String[] requestingUserRoles) {
        // Korrigiert: Korrekt benannten Parameter verwenden
        return accessGranted(resource, requestingUserRoles);
    }

    // Alternative: Methode schwieriger falsch zu verwenden machen
    public boolean checkAccessForUser(String resource, User user) {
        String[] userRoles = user.getRoles();  // Rollen vom Benutzerobjekt holen
        return accessGranted(resource, userRoles);
    }

    private boolean accessGranted(String resource, String[] roles) {
        for (String role : roles) {
            if (hasPermission(role, resource)) {
                return true;
            }
        }
        return false;
    }
}

// Korrigiert: Unterscheidbare Variablennamen verhindern Copy-Paste-Fehler
public class SecureCopyPaste {

    public void processUserData(User fromUser, User toUser) {
        // Korrigiert: Unterscheidbare Namen machen Fehler offensichtlich
        validatePermissions(fromUser);
        copyData(fromUser, toUser);
    }

    public void updateRecords(Record recordToDelete, Record recordToInsert) {
        // Korrigiert: Namen zeigen Zweck an
        database.delete(recordToDelete);
        database.insert(recordToInsert);
    }
}
// Korrigiert: Korrekte Variablen mit klarer Dokumentation
#include <string.h>

struct packet_header {
    int type;
    int length;
    char data[256];
};

static const struct packet_header DEFAULT_HEADER = {0, 0, {0}};

// Korrigiert: Korrekte Zielvariable
void secure_init_packet(struct packet_header* dest_packet) {
    // Korrigiert: Von Vorlage ZUM Ziel kopieren
    memcpy(dest_packet, &DEFAULT_HEADER, sizeof(struct packet_header));
}

// Korrigiert: Korrekter Pointer mit klarer Benennung
void secure_process(struct data* input_data, struct data* output_data) {
    struct data* processed_temp = NULL;

    if (validate(input_data)) {
        processed_temp = allocate_data();
        // ... Verarbeitung ...
    }

    // Korrigiert: Die richtige Variable prüfen
    if (processed_temp != NULL) {
        copy_data(output_data, processed_temp);
        free_data(processed_temp);
    }
}

// const verwenden um versehentliche Modifikation zu verhindern
void init_from_template(struct packet_header* dest,
                        const struct packet_header* template) {
    // template ist const - kann nicht versehentlich als Ziel verwendet werden
    memcpy(dest, template, sizeof(struct packet_header));
}
# Korrigiert: Klare Variablenbenennung
def secure_batch_process(items_to_process, already_completed):
    processed = []

    # Korrigiert: Klarer Name zeigt Absicht an
    for item in items_to_process:
        result = process(item)
        processed.append(result)

    return processed

# Korrigiert: Explizite Validierungslogik
class SecureAuth:

    def __init__(self):
        self.active_tokens = {}
        self.revoked_tokens = {}

    def validate_token(self, token):
        # Korrigiert: Explizite zweistufige Validierung
        is_active = token in self.active_tokens
        is_revoked = token in self.revoked_tokens

        # Token muss aktiv UND nicht widerrufen sein
        return is_active and not is_revoked

# Korrigiert: Eindeutige Parameternamen
def calculate_discount(original_price, discount_percentage, existing_discount=0):
    # Korrigiert: Klar welcher Preis zu verwenden ist
    price_before_discount = original_price
    calculated = price_before_discount * (1 - discount_percentage)
    return calculated
// Korrigiert: Explizite Variablenauswahl
function secureUserUpdate(currentUser, newData, isAdmin = false) {
    const adminDefaults = {
        role: 'admin',
        permissions: ['all']
    };

    const userDefaults = {
        role: 'user',
        permissions: ['read']
    };

    // Korrigiert: Explizite Auswahl basierend auf Bedingung
    const defaultsToUse = isAdmin ? adminDefaults : userDefaults;
    return Object.assign({}, defaultsToUse, newData);
}

// Korrigiert: Auf korrektem Array mit Validierung arbeiten
function secureRemoveItem(sourceList, targetList, itemId) {
    const index = sourceList.findIndex(item => item.id === itemId);

    if (index !== -1) {
        // Korrigiert: Aus Quelle entfernen, optional zu Ziel verschieben
        const [removed] = sourceList.splice(index, 1);
        if (targetList) {
            targetList.push(removed);  // Archivieren wenn Ziel angegeben
        }
    }
}

// Best Practice: Objektparameter verwenden um Variablenverwechslung zu verhindern
function updateItem({ fromList, toList, itemId }) {
    // Benannte Parameter machen klar welches welches ist
    const index = fromList.findIndex(item => item.id === itemId);
    if (index !== -1) {
        const [item] = fromList.splice(index, 1);
        toList.push(item);
    }
}

CVE-Beispiele

  • CVE-2005-2548: Linux-Kernel-Code spezifizierte die falsche Variable in einem initialen Argument, was zu einer NULL-Pointer-Dereferenzierungs-Schwachstelle führte.
  • CVE-2006-1052: Falsche Variable im Vergleich verwendet, führte zur Authentifizierungsumgehung.

Referenzen

  1. MITRE Corporation. "CWE-688: Function Call With Incorrect Variable or Reference as Argument." https://cwe.mitre.org/data/definitions/688.html
  2. CERT C Coding Standard. "EXP37-C. Call functions with the correct number and type of arguments."