Aikido

Warum globale Variablen Datenlecks in Node.js-Servern verursachen

Sicherheit

Regel
Vermeiden Sie unbeabsichtigte globale Variable caching.In Node.js
und Python Server, globale Variablen bleiben bestehen über
Anfragen, verursacht Daten Datenlecks und Rennen Bedingungen.

Unterstützte Sprachen: JavaScript, TypeScript, Python

Einleitung

Globale Variablen in Node.js-Servern bleiben über die gesamte Lebensdauer des Prozesses bestehen, nicht nur für eine einzelne Anfrage. Wenn Request-Handler Benutzerdaten in globalen Variablen speichern, bleiben diese Daten für nachfolgende Anfragen von verschiedenen Benutzern zugänglich. Dies führt zu Sicherheitslücken, bei denen Sitzungsdaten, Authentifizierungs-Tokens oder persönliche Informationen von Benutzer A an Benutzer B gelangen können.

Warum es wichtig ist

Sicherheitsimplikationen (Datenlecks): Globale Variablen, die benutzerspezifische Daten cachen, erzeugen Cross-Request-Datenlecks. Der Authentifizierungsstatus, die Sitzungsdaten oder persönliche Informationen eines Benutzers werden für andere Benutzer sichtbar, was Datenschutz- und Sicherheitsgrenzen verletzt.

Race Conditions: Wenn mehrere gleichzeitige Anfragen dieselbe globale Variable modifizieren, besteht eine hohe Wahrscheinlichkeit für unvorhersehbares Verhalten. Die Daten von Benutzer A können während der Verarbeitung durch die Anfrage von Benutzer B überschrieben werden, was zu falschen Berechnungen, einem korrupten Zustand oder dazu führen kann, dass Benutzer die Daten des jeweils anderen sehen.

Debugging-Komplexität: Probleme, die durch globales Variablen-Caching verursacht werden, sind notorisch schwer zu reproduzieren, da sie von Request-Timing und Parallelität abhängen. Fehler treten in der Produktion unter Last sporadisch auf, zeigen sich aber selten bei Single-Threaded-Entwicklungstests.

Speicherlecks: Globale Variablen, die Daten ohne Bereinigung ansammeln, wachsen im Laufe der Zeit unbegrenzt an. Jede Anfrage fügt globalen Caches oder Arrays weitere Daten hinzu, was schließlich den Serverspeicher erschöpft und Prozessneustarts erfordert.

Code-Beispiele

❌ Nicht konform:

let currentUser = null;
let requestData = {};

app.get('/profile', async (req, res) => {
    currentUser = await getUserById(req.userId);
    requestData = req.body;

    const profile = await buildUserProfile(currentUser);
    res.json(profile);
});

function buildUserProfile(user) {
    return {
        name: currentUser.name,
        data: requestData
    };
}

Warum es falsch ist: Die globalen Variablen currentUser und requestData bleiben über Anfragen hinweg bestehen. Wenn mehrere Anfragen gleichzeitig ausgeführt werden, kann die Anfrage von Benutzer B currentUser überschreiben, während buildUserProfile() von Benutzer A noch ausgeführt wird, wodurch Benutzer A die Daten von Benutzer B sieht.

✅ Konform:

app.get('/profile', async (req, res) => {
    const currentUser = await getUserById(req.userId);
    const requestData = req.body;

    const profile = buildUserProfile(currentUser, requestData);
    res.json(profile);
});

function buildUserProfile(user, data) {
    return {
        name: user.name,
        data: data
    };
}

Warum das wichtig ist: Alle anforderungsspezifischen Daten werden in lokalen Variablen gespeichert, die auf den Request-Handler beschränkt sind. Jede Anfrage hat einen isolierten Zustand, der nicht auf andere gleichzeitige Anfragen übergreifen kann. Funktionen empfangen Daten über Parameter, anstatt auf den globalen Zustand zuzugreifen, wodurch Race Conditions eliminiert werden.

Fazit

Halten Sie alle anfragespezifischen Daten in lokalen Variablen oder Request-Objekten, die von Ihrem Framework bereitgestellt werden. Verwenden Sie globale Variablen nur für wirklich gemeinsam genutzte Zustände wie Konfigurationen, Verbindungspools oder Read-only-Caches. Wenn ein globaler Zustand erforderlich ist, verwenden Sie geeignete Parallelitätskontrollen und stellen Sie sicher, dass die Daten niemals benutzerspezifisch sind.

FAQs

Haben Sie Fragen?

Wann ist die Verwendung globaler Variablen in Node.js unbedenklich?

Globale Variablen sind sicher für schreibgeschützte Daten, die für alle Anfragen gelten: Anwendungskonfigurationen, Datenbank-Verbindungspools, kompilierte Templates oder gemeinsam genutzte Dienstprogramme. Speichern Sie niemals anfrage- oder benutzerspezifische Daten global. Wenn Sie Daten global cachen müssen, stellen Sie sicher, dass sie korrekt verschlüsselt sind und der Zugriff Thread-sicher ist, oder verwenden Sie geeignete Caching-Lösungen wie Redis.

Was ist mit Variablen auf Modulebene, die nicht explizit global sind?

Variablen auf Modulebene (const, let, var im Dateibereich) verhalten sich in Node.js genau wie globale Variablen. Sie bleiben über alle Anfragen hinweg bestehen und werden von allen gleichzeitigen Anfrage-Handlern geteilt. Es gelten die gleichen Risiken für Datenlecks und Race Conditions. Behandeln Sie Variablen auf Modulebene mit der gleichen Vorsicht wie explizite globale Variablen.

Wie teile ich Daten zwischen Middleware und Route-Handlern?

Verwenden Sie Request-Objekt-Eigenschaften, die von Ihrem Framework bereitgestellt werden. Express bietet req.locals oder benutzerdefinierte Eigenschaften auf req. Fastify verfügt über request.decorateRequest(). Diese Objekte sind Request-scoped und werden nach Abschluss der Anfrage automatisch bereinigt, wodurch Lecks zwischen Anfragen verhindert werden.

Was ist mit Singleton-Patterns und Klasseninstanzen?

Singleton-Instanzen auf Modulebene sind globaler Zustand. Wenn sie anforderungsspezifische Daten enthalten, gelten die gleichen Probleme. Entwerfen Sie Singletons so, dass sie zustandslos sind oder nur Konfigurationen enthalten. Für zustandsbehaftete Operationen erstellen Sie neue Instanzen pro Anfrage oder verwenden Sie Factory-Muster, die Isolation gewährleisten.

Wie erkenne ich diese Probleme während der Entwicklung?

Führen Sie Lasttests mit gleichzeitigen Anfragen unter Verwendung verschiedener Benutzerkontexte durch. Race Conditions und Datenlecks treten oft nicht bei sequenziellen Tests auf. Verwenden Sie Tools wie Apache Bench oder autocannon, um gleichzeitige Last zu erzeugen. Fügen Sie Logging hinzu, das Request-IDs enthält, um zu verfolgen, wann Daten einer Anfrage in einer anderen erscheinen.

Gilt dies für serverlose Funktionen wie AWS Lambda?

Teilweise. Jeder Lambda-Aufruf erhält eine frische Ausführungsumgebung, aber der Container kann über mehrere Aufrufe hinweg wiederverwendet werden. Globale Variablen bleiben zwischen Aufrufen bestehen, die denselben Container wiederverwenden. Verlassen Sie sich nicht darauf, dass globale Variablen zurückgesetzt werden. Befolgen Sie dieselben Praktiken: Halten Sie Anfragedaten im lokalen Bereich.

Was ist mit Python WSGI/ASGI-Anwendungen?

Es gelten die gleichen Prinzipien. Python-Webserver laufen multi-threaded oder asynchron, sodass Variablen auf Modulebene über Anfragen hinweg geteilt werden. Flasks g-Objekt und FastAPIs Dependency Injection bieten Request-scoped Storage. Django verfügt über Request-Objekte. Verwenden Sie von Frameworks bereitgestellte Mechanismen anstelle von Modul-Globals für Request-Daten.

Werden Sie jetzt sicher.

Sichern Sie Ihren Code, Ihre Cloud und Ihre Laufzeit in einem zentralen System.
Finden und beheben Sie Schwachstellen schnell und automatisch.

Keine Kreditkarte erforderlich | Scan-Ergebnisse in 32 Sek.