Aufrufbares Steuerelement in Multi-Thread-Kontext mit nicht-finaler statischer speicherbarer oder Member-Element
Beschreibung
Aufrufbares Steuerelement in Multi-Thread-Kontext mit nicht-finaler statischer speicherbarer oder Member-Element tritt auf, wenn eine Funktion oder Methode in einer Multi-Thread-Umgebung operiert, aber eine unsichere nicht-finale statische Variable oder ein veränderbares Member-Datenelement besitzt. Wenn mehrere Threads ohne ordnungsgemäße Synchronisation auf gemeinsamen veränderbaren Zustand zugreifen und diesen modifizieren, treten Race Conditions auf. Diese Race Conditions können zu Datenkorruption, inkonsistentem Zustand und unvorhersehbarem Verhalten führen, das Sicherheitsimplikationen haben kann.
Risiko
Diese Schwäche erzeugt Zuverlässigkeits- und Sicherheitsrisiken. Race Conditions bei sicherheitskritischen Daten können zu Authentifizierungsumgehungen, Autorisierungsfehlern oder Datenlecks führen. Beispielsweise könnte eine gemeinsam genutzte Variable, die den Authentifizierungsstatus verfolgt, korrumpiert werden und unbefugten Zugriff ermöglichen. TOCTOU-Schwachstellen (Time-of-Check to Time-of-Use) entstehen häufig aus unsynchronisiertem gemeinsamen Zustand. Die nicht-deterministische Natur von Race Conditions macht sie schwer durch Testen zu erkennen, aber sie können zuverlässig ausgenutzt werden. In Sicherheitskontexten können Angreifer möglicherweise spezifische Thread-Verschachtelungen auslösen, um die Schwachstelle auszunutzen.
Lösung
Verwenden Sie ordnungsgemäße Synchronisationsmechanismen: Locks, Mutexe, Semaphoren oder synchronized-Blöcke. Machen Sie gemeinsam genutzte Variablen final/unveränderlich, wo möglich. Verwenden Sie thread-sichere Datenstrukturen (ConcurrentHashMap, AtomicInteger usw.). Wenden Sie das Prinzip der Thread-Confinement an - vermeiden Sie das Teilen von Zustand zwischen Threads. Verwenden Sie das volatile-Schlüsselwort für Sichtbarkeit (aber nicht Atomizität). Erwägen Sie lock-freie Algorithmen mit atomaren Operationen. Setzen Sie statische Analysetools ein, die Threading-Probleme erkennen. Verwenden Sie thread-sichere Design-Patterns wie unveränderliche Objekte oder Thread-Local-Storage.
Häufige Auswirkungen
| Auswirkung | Details |
|---|---|
| Verfügbarkeit | Bereich: Verfügbarkeit Reduzierte Zuverlässigkeit - Race Conditions können Abstürze, Hänger oder unvorhersehbares Verhalten verursachen. |
| Integrität | Bereich: Integrität Anwendungsdaten modifizieren - Gleichzeitige Modifikationen ohne Synchronisation können gemeinsame Daten korrumpieren. |
| Zugriffskontrolle | Bereich: Zugriffskontrolle Schutzmechanismus umgehen - Race Conditions bei Sicherheitszustand können zu Authentifizierungs-/Autorisierungsumgehungen führen. |
Beispielcode
Anfälliger Code
// Anfällig: Nicht-finale statische Variable in Multi-Thread-Kontext
public class VulnerableSessionManager {
// Anfällig: Veränderbarer statischer Zustand, geteilt über alle Threads
private static Map<String, Session> activeSessions = new HashMap<>();
// Anfällig: Nicht-finaler statischer Zähler
private static int sessionCount = 0;
public static Session getSession(String sessionId) {
// Anfällig: Unsynchronisiertes Lesen
// Ein anderer Thread könnte die Map gleichzeitig modifizieren
return activeSessions.get(sessionId);
}
public static void addSession(String sessionId, Session session) {
// Anfällig: Check-then-act Race Condition
if (!activeSessions.containsKey(sessionId)) {
activeSessions.put(sessionId, session);
sessionCount++; // Nicht-atomares Inkrement
}
}
public static void removeSession(String sessionId) {
// Anfällig: Unsynchronisierte Modifikation
if (activeSessions.containsKey(sessionId)) {
activeSessions.remove(sessionId);
sessionCount--; // Nicht-atomares Dekrement
}
}
}
// Race-Condition-Szenario:
// Thread 1: ruft addSession("sess1", session1) auf
// Thread 2: ruft addSession("sess1", session2) gleichzeitig auf
// Beide prüfen containsKey() -> false (Race)
// Beide fügen ihre Session hinzu -> eine überschreibt die andere
// sessionCount wird zweimal erhöht, aber nur eine Session existiert
# Anfällig: Gemeinsamer veränderbarer Zustand in Python Multi-Threading
import threading
class VulnerableRateLimiter:
# Anfällig: Gemeinsamer veränderbarer Zustand ohne Locking
request_counts = {} # Klassenvariable, geteilt von allen Instanzen/Threads
total_requests = 0
def check_rate_limit(self, client_id, limit=100):
# Anfällig: Read-modify-write ohne Synchronisation
current = self.request_counts.get(client_id, 0)
if current >= limit:
return False # Ratenlimitiert
# Race-Condition-Fenster hier!
# Ein anderer Thread könnte request_counts[client_id] modifizieren
self.request_counts[client_id] = current + 1
self.total_requests += 1 # Nicht-atomares Inkrement
return True
# Mehrere Threads, die Ratenlimit prüfen, können das Limit überschreiten
# aufgrund von Race Condition zwischen Lesen und Schreiben
// Anfällig: C# mit gemeinsam genutztem veränderbarem Zustand
public class VulnerableAuthenticationState
{
// Anfällig: Nicht-readonly statische Felder
private static Dictionary<string, User> authenticatedUsers = new Dictionary<string, User>();
private static int failedLoginAttempts = 0;
public static bool IsAuthenticated(string token)
{
// Anfällig: Dictionary ist nicht thread-sicher
return authenticatedUsers.ContainsKey(token);
}
public static void Authenticate(string token, User user)
{
// Anfällig: Race Condition
if (!authenticatedUsers.ContainsKey(token))
{
authenticatedUsers[token] = user;
}
}
public static void RecordFailedLogin()
{
// Anfällig: Nicht-atomares Inkrement
failedLoginAttempts++;
// Könnte einige Fehler wegen Race nicht zählen
if (failedLoginAttempts > 10)
{
TriggerAlert();
}
}
}
Korrigierter Code
// Korrigiert: Ordnungsgemäße Synchronisation für Multi-Thread-Kontext
public class FixedSessionManager {
// Korrigiert: ConcurrentHashMap für thread-sichere Operationen verwenden
private static final ConcurrentHashMap<String, Session> activeSessions =
new ConcurrentHashMap<>();
// Korrigiert: AtomicInteger für thread-sicheres Zählen verwenden
private static final AtomicInteger sessionCount = new AtomicInteger(0);
public static Session getSession(String sessionId) {
// Korrigiert: ConcurrentHashMap ist thread-sicher
return activeSessions.get(sessionId);
}
public static void addSession(String sessionId, Session session) {
// Korrigiert: Atomare putIfAbsent-Operation
Session existing = activeSessions.putIfAbsent(sessionId, session);
if (existing == null) {
// Nur inkrementieren, wenn wir tatsächlich eine neue Session hinzugefügt haben
sessionCount.incrementAndGet();
}
}
public static void removeSession(String sessionId) {
// Korrigiert: Atomares remove gibt den entfernten Wert zurück
Session removed = activeSessions.remove(sessionId);
if (removed != null) {
sessionCount.decrementAndGet();
}
}
public static int getSessionCount() {
return sessionCount.get();
}
}
# Korrigiert: Thread-sichere Implementierung mit Locks
import threading
from collections import defaultdict
class FixedRateLimiter:
def __init__(self):
# Korrigiert: Instanzvariablen mit Lock-Schutz
self._request_counts = defaultdict(int)
self._total_requests = 0
self._lock = threading.Lock()
def check_rate_limit(self, client_id, limit=100):
# Korrigiert: Lock für gesamte Check-and-update-Operation erwerben
with self._lock:
current = self._request_counts[client_id]
if current >= limit:
return False
self._request_counts[client_id] = current + 1
self._total_requests += 1
return True
def get_request_count(self, client_id):
with self._lock:
return self._request_counts[client_id]
// Korrigiert: Thread-sichere C#-Implementierung
public class FixedAuthenticationState
{
// Korrigiert: ConcurrentDictionary verwenden
private static readonly ConcurrentDictionary<string, User> authenticatedUsers =
new ConcurrentDictionary<string, User>();
// Korrigiert: Interlocked für atomare Operationen verwenden
private static int failedLoginAttempts = 0;
public static bool IsAuthenticated(string token)
{
// Korrigiert: ConcurrentDictionary ist thread-sicher
return authenticatedUsers.ContainsKey(token);
}
public static bool Authenticate(string token, User user)
{
// Korrigiert: TryAdd ist atomar
return authenticatedUsers.TryAdd(token, user);
}
public static void RecordFailedLogin()
{
// Korrigiert: Interlocked.Increment ist atomar
int currentAttempts = Interlocked.Increment(ref failedLoginAttempts);
if (currentAttempts > 10)
{
TriggerAlert();
}
}
public static void ResetFailedLoginCount()
{
Interlocked.Exchange(ref failedLoginAttempts, 0);
}
}
CVE-Beispiele
Race Conditions im Zusammenhang mit unsynchronisiertem gemeinsamem Zustand haben zu vielen Schwachstellen beigetragen, obwohl diese spezifische CWE oft unter CWE-362 (Concurrent Execution) für CVE-Mapping-Zwecke kategorisiert wird.
Verwandte CWEs
- CWE-662: Improper Synchronization (Eltern)
- CWE-557: Concurrency Issues (Kategoriemitglied)
- CWE-362: Concurrent Execution Using Shared Resource with Improper Synchronization (verwandt)
Referenzen
-
MITRE Corporation. "CWE-1058: Invokable Control Element in Multi-Thread Context with non-Final Static Storable or Member Element." https://cwe.mitre.org/data/definitions/1058.html
-
Oracle. "Java Concurrency Tutorial."
-
Götz, Brian. "Java Concurrency in Practice."