Übermäßige Abhängigkeit von globalen Variablen

Beschreibung

Übermäßige Abhängigkeit von globalen Variablen tritt auf, wenn Code so strukturiert ist, dass er zu stark auf die Verwendung oder das Setzen globaler Variablen an verschiedenen Stellen im Code angewiesen ist, anstatt die zugehörigen Informationen in einem engeren, lokaleren Kontext zu bewahren. Globale Variablen sind von überall im Programm zugänglich, was die Verfolgung ihres Zustands erschwert und versteckte Abhängigkeiten zwischen verschiedenen Teilen des Codes erzeugt. Dies verletzt Prinzipien der Kapselung und macht den Code schwieriger zu verstehen, zu testen und zu warten.

Risiko

Übermäßige Verwendung globaler Variablen hat Sicherheitsimplikationen. Globaler Zustand kann von überall aus modifiziert werden, was es schwierig macht sicherzustellen, dass Invarianten eingehalten werden. Race Conditions sind wahrscheinlicher, wenn mehrere Threads auf globalen Zustand zugreifen. Sicherheitssensible Daten in globalen Variablen sind stärker exponiert. Versteckte Abhängigkeiten zwischen Komponenten können unerwartetes Sicherheitsverhalten verursachen. Das Testen auf Sicherheitsprobleme wird durch globalen Zustand erschwert. Code-Reviews können nicht einfach alle Stellen verfolgen, an denen sich der globale Zustand ändert. Das Debugging von Sicherheitsvorfällen wird durch nicht-lokale Effekte erschwert.

Lösung

Minimieren Sie die Verwendung globaler Variablen; bevorzugen Sie lokale Variablen und Parameterübergabe. Kapseln Sie Zustand in Objekten mit kontrollierten Zugriffsmethoden. Verwenden Sie Dependency Injection, um gemeinsam genutzten Zustand explizit bereitzustellen. Wenn Globals notwendig sind, verwenden Sie ordnungsgemäße Synchronisation für Thread-Sicherheit. Erwägen Sie die Verwendung von Konstanten anstelle von Variablen für unveränderliche globale Daten. Wenden Sie das Prinzip der geringsten Privilegien an - beschränken Sie den Geltungsbereich auf das tatsächlich Notwendige. Verwenden Sie statische Analysetools, um übermäßige Verwendung globaler Variablen zu erkennen. Refaktorieren Sie Legacy-Code schrittweise, um globale Abhängigkeiten zu reduzieren.

Häufige Auswirkungen

AuswirkungDetails
SonstigesBereich: Sonstiges

Reduzierte Wartbarkeit - Globaler Zustand erzeugt versteckte Abhängigkeiten, die die Wartung erschweren.
SonstigesBereich: Sonstiges

Erhöhte Analysekomplexität - Datenfluss durch globale Variablen ist schwer zu verfolgen.
IntegritätBereich: Integrität

Unerwarteter Zustand - Globaler Zustand kann unerwartet von überall modifiziert werden.

Beispielcode und Lösung

Verwundbarer Code

// Verwundbar: Übermäßige globale Variablen
#include <stdio.h>
#include <string.h>
#include <stdbool.h>

// Globale Variablen im gesamten Code verstreut
char g_aktueller_benutzer[100];
int g_berechtigungsstufe;
bool g_ist_authentifiziert;
char g_session_token[256];
int g_fehlgeschlagene_anmeldeversuche;
bool g_konto_gesperrt;
char g_letzter_fehler[500];
void* g_datenbankverbindung;
char g_config_pfad[256];
int g_log_level;

// Funktionen modifizieren Globals von überall
void verwundbare_anmeldung(const char* benutzername, const char* passwort) {
    // Modifiziert mehrere Globals
    if (verify_password(benutzername, passwort)) {
        g_ist_authentifiziert = true;
        strcpy(g_aktueller_benutzer, benutzername);
        g_berechtigungsstufe = get_user_permission(benutzername);
        generate_token(g_session_token);
        g_fehlgeschlagene_anmeldeversuche = 0;  // Zurücksetzen
    } else {
        g_ist_authentifiziert = false;
        g_fehlgeschlagene_anmeldeversuche++;  // Global inkrementieren
        if (g_fehlgeschlagene_anmeldeversuche >= 5) {
            g_konto_gesperrt = true;  // Weitere Global setzen
        }
    }
}

void verwundbare_anfrage_verarbeiten(const char* aktion) {
    // Verlasst sich darauf, dass Globals irgendwo anders korrekt gesetzt wurden
    if (!g_ist_authentifiziert) {
        strcpy(g_letzter_fehler, "Nicht authentifiziert");
        return;
    }

    if (g_berechtigungsstufe < 2) {
        strcpy(g_letzter_fehler, "Unzureichende Berechtigungen");
        return;
    }

    // Aktion verarbeiten...
}

// Problem: Jede Funktion kann jede globale Variable modifizieren
// Race Conditions wenn mehrere Threads diese verwenden
void verwundbare_ändere_funktion() {
    // Kann Sicherheitszustand willkürlich modifizieren!
    g_ist_authentifiziert = true;  // Sicherheitsumgehung!
    g_berechtigungsstufe = 999;    // Privilegieneskalation!
}
// Verwundbar: Java mit übermäßigem statischem/globalem Zustand
public class VerwundbarerGlobalerZustand {

    // Veränderliche statische Felder = globaler Zustand
    public static User aktuellerBenutzer;
    public static Session aktiveSitzung;
    public static int berechtigungsstufe;
    public static boolean istAdmin;
    public static DatabaseConnection dbVerbindung;
    public static Configuration config;
    public static Logger logger;

    // Thread-unsicherer globaler Zugriff
    public static Map<String, Object> cache = new HashMap<>();
    public static List<String> auditLog = new ArrayList<>();
}

public class VerwundbarerAuthService {

    public void anmelden(String benutzername, String passwort) {
        if (verifyCredentials(benutzername, passwort)) {
            // Setzt globalen Zustand
            VerwundbarerGlobalerZustand.aktuellerBenutzer = loadUser(benutzername);
            VerwundbarerGlobalerZustand.aktiveSitzung = createSession();
            VerwundbarerGlobalerZustand.berechtigungsstufe = getPermission(benutzername);
            VerwundbarerGlobalerZustand.istAdmin = checkAdmin(benutzername);
        }
    }

    public void abmelden() {
        // Löscht globalen Zustand
        VerwundbarerGlobalerZustand.aktuellerBenutzer = null;
        VerwundbarerGlobalerZustand.aktiveSitzung = null;
        VerwundbarerGlobalerZustand.berechtigungsstufe = 0;
        VerwundbarerGlobalerZustand.istAdmin = false;
    }
}

Sichere Lösung

// Sicher: Strukturierten Kontext statt Globals verwenden
#include <stdio.h>
#include <string.h>
#include <stdbool.h>

// Session-Zustand in Struktur kapseln
typedef struct {
    char benutzername[100];
    int berechtigungsstufe;
    bool ist_authentifiziert;
    char session_token[256];
    int fehlgeschlagene_versuche;
    bool konto_gesperrt;
} SessionKontext;

// Konfiguration als nur-lesbar nach Initialisierung
typedef struct {
    char config_pfad[256];
    int log_level;
    int max_anmeldeversuche;
} AppConfig;

// Kontext explizit übergeben statt Globals zu verwenden
int sichere_anmeldung(
    SessionKontext* ctx,
    const AppConfig* config,
    const char* benutzername,
    const char* passwort) {

    if (ctx->konto_gesperrt) {
        return -1;
    }

    if (verify_password(benutzername, passwort)) {
        ctx->ist_authentifiziert = true;
        strncpy(ctx->benutzername, benutzername, sizeof(ctx->benutzername) - 1);
        ctx->berechtigungsstufe = get_user_permission(benutzername);
        generate_token(ctx->session_token);
        ctx->fehlgeschlagene_versuche = 0;
        return 0;
    } else {
        ctx->ist_authentifiziert = false;
        ctx->fehlgeschlagene_versuche++;
        if (ctx->fehlgeschlagene_versuche >= config->max_anmeldeversuche) {
            ctx->konto_gesperrt = true;
        }
        return -1;
    }
}

int sichere_anfrage_verarbeiten(
    const SessionKontext* ctx,
    const char* aktion,
    char* fehler_buffer,
    size_t fehler_größe) {

    if (!ctx->ist_authentifiziert) {
        strncpy(fehler_buffer, "Nicht authentifiziert", fehler_größe);
        return -1;
    }

    if (ctx->berechtigungsstufe < 2) {
        strncpy(fehler_buffer, "Unzureichende Berechtigungen", fehler_größe);
        return -1;
    }

    // Aktion mit explizitem Kontext verarbeiten
    return 0;
}

// Jede Anfrage erhält ihren eigenen Kontext - kein globaler Zustand
void sichere_anfrage_behandeln(const AppConfig* config) {
    SessionKontext ctx = {0};  // Lokaler Kontext

    sichere_anmeldung(&ctx, config, "benutzer", "passwort");
    sichere_anfrage_verarbeiten(&ctx, "aktion", NULL, 0);

    // Kontext wird automatisch bereinigt wenn Funktion zurückkehrt
}
// Sicher: Dependency Injection und gekapselter Zustand
public class SessionKontext {
    private final String benutzername;
    private final int berechtigungsstufe;
    private final boolean admin;
    private final String sessionToken;

    // Unveränderlich nach Erstellung
    public SessionKontext(String benutzername, int berechtigungsstufe,
                          boolean admin, String sessionToken) {
        this.benutzername = benutzername;
        this.berechtigungsstufe = berechtigungsstufe;
        this.admin = admin;
        this.sessionToken = sessionToken;
    }

    // Nur Getter, keine Setter
    public String getBenutzername() { return benutzername; }
    public int getBerechtigungsstufe() { return berechtigungsstufe; }
    public boolean isAdmin() { return admin; }
    public String getSessionToken() { return sessionToken; }
}

// Sicher: Services erhalten Abhängigkeiten durch Konstruktor
public class SichererAuthService {

    private final UserRepository userRepository;
    private final SessionStore sessionStore;
    private final PasswordEncoder passwordEncoder;

    // Abhängigkeiten injiziert
    public SichererAuthService(
            UserRepository userRepository,
            SessionStore sessionStore,
            PasswordEncoder passwordEncoder) {
        this.userRepository = userRepository;
        this.sessionStore = sessionStore;
        this.passwordEncoder = passwordEncoder;
    }

    public SessionKontext anmelden(String benutzername, String passwort) {
        User user = userRepository.findByUsername(benutzername)
            .orElseThrow(() -> new AuthenticationException("Ungültige Anmeldedaten"));

        if (!passwordEncoder.matches(passwort, user.getPasswordHash())) {
            throw new AuthenticationException("Ungültige Anmeldedaten");
        }

        String token = generateToken();
        SessionKontext kontext = new SessionKontext(
            user.getUsername(),
            user.getPermissionLevel(),
            user.isAdmin(),
            token
        );

        sessionStore.save(token, kontext);
        return kontext;
    }
}

CVE-Beispiele

Übermäßige globale Variablen haben zu verschiedenen Sicherheitslücken beigetragen, bei denen globaler Zustand unsachgemäß modifiziert wurde, was zu Authentifizierungsumgehungen, Privilegieneskalation und Race Conditions führte.


Verwandte CWEs

  • CWE-1076: Unzureichende Einhaltung erwarteter Konventionen (Eltern)
  • CWE-1006: Schlechte Programmierpraktiken (Kategoriemitglied)
  • CWE-362: Nebenläufige Ausführung mit gemeinsam genutzter Ressource ohne ordnungsgemäße Synchronisation (verwandt)

Referenzen

  1. MITRE Corporation. "CWE-1108: Excessive Reliance on Global Variables." https://cwe.mitre.org/data/definitions/1108.html

  2. Martin, Robert C. "Clean Code" - Funktionen sollten keine globalen Variablen verwenden.