Inkorrekte Short-Circuit-Auswertung
Beschreibung
Inkorrekte Short-Circuit-Auswertung ist eine Logikschwachstelle, bei der bedingte Anweisungen mit mehreren Ausdrücken Nebeneffekte in nicht-führenden Ausdrücken enthalten, die aufgrund der Short-Circuit-Auswertung möglicherweise nicht ausgeführt werden. In den meisten Programmiersprachen stoppt logisches AND (&&) die Auswertung, wenn der erste Operand false ist, und logisches OR (||) stoppt, wenn der erste Operand true ist. Wenn nachfolgende Ausdrücke Nebeneffekte (Zuweisungen, Funktionsaufrufe, Inkremente) enthalten, treten diese Nebeneffekte möglicherweise nicht auf, was zu unerwartetem Programmzustand führt.
Risiko
Short-Circuit-Auswertungsfehler erzeugen unvorhersehbare Programmzustände mit Sicherheitsimplikationen. Wenn sicherheitskritische Operationen (wie Berechtigungsprüfungen, Audit-Logging oder Zustandsinitialisierung) in nicht-führenden bedingten Ausdrücken platziert werden, können sie unerwartet übersprungen werden. Dies kann zu uninitialisierten Variablen, umgangenen Sicherheitsprüfungen oder unvollständigen Zustandsaktualisierungen führen. Die Schwachstelle ist besonders tückisch, weil der Code in den meisten Fällen korrekt funktioniert, aber unter bestimmten Bedingungen versagt.
Lösung
Vermeiden Sie das Platzieren von Ausdrücken mit Nebeneffekten in bedingten Anweisungen, insbesondere an nicht-führenden Positionen. Extrahieren Sie Nebeneffekt-Operationen in separate Anweisungen vor der Bedingung. Wenn ein Funktionsaufruf wirklich Teil der Bedingung ist, stellen Sie sicher, dass er keine kritischen Nebeneffekte hat oder dass seine Ausführung nicht vom Short-Circuit-Verhalten abhängt. Verwenden Sie explizite bedingte Prüfungen anstelle der Abhängigkeit von der Auswertungsreihenfolge. Überprüfen Sie Code auf Inkrement/Dekrement-Operatoren, Zuweisungen und Funktionsaufrufe innerhalb bedingter Ausdrücke.
Häufige Auswirkungen
| Auswirkung | Details |
|---|---|
| Integrität | Bereich: Integrität Unerwarteter Zustand - Programm gerät in undefinierten oder inkonsistenten Zustand, wenn Nebeneffekte aufgrund von Short-Circuiting nicht ausgeführt werden. |
| Vertraulichkeit | Bereich: Vertraulichkeit Informationsoffenlegung - Uninitialisierte Variablen können sensible Restdaten enthalten. |
| Verfügbarkeit | Bereich: Verfügbarkeit DoS: Absturz - Verwendung uninitialisierter oder falsch initialisierter Daten kann Abstürze verursachen. |
Beispielcode
Verwundbarer Code
// Verwundbar: Dekrement in Bedingung wird möglicherweise nicht ausgeführt
#define ADMIN_PRIV 0
#define STANDARD_PRIV 1
#define NUM_USERS 5
int privileges[NUM_USERS];
void initializePrivileges() {
int i = NUM_USERS;
// Verwundbar: Zuweisung im zweiten Operanden wird übersprungen wenn i 0 wird
while (--i && (privileges[i] = STANDARD_PRIV)) {
// Wenn --i zu 0 (false) ausgewertet wird, findet die Zuweisung nicht statt
// privileges[0] wird nie initialisiert!
}
// privileges[0] enthält uninitialisierten/vorherigen Wert
}
// Verwundbar: Sicherheitsprüfung im zweiten Operanden kann übersprungen werden
int isValidRequest = 0;
int isAuthenticated = 0;
int auditLogged = 0;
void processRequest(int requestType, int userId) {
// Verwundbar: Audit-Logging wird übersprungen wenn erste Bedingung true ist
if (requestType == FAST_PATH || (auditLogged = logRequest(userId))) {
// Für FAST_PATH-Anfragen wird Audit-Logging übersprungen!
processData();
}
}
// Verwundbar: Berechtigungsprüfung unter bestimmten Bedingungen übersprungen
void accessResource(int urgentMode, int userId) {
// Verwundbar: checkPermission() wird nicht aufgerufen wenn urgentMode true ist
if (urgentMode || checkPermission(userId)) {
// Dringender Modus umgeht Berechtigungsprüfung!
readSensitiveData();
}
}
Gefixter Code
// Gefixt: Nebeneffekte außerhalb der Bedingung verschoben
#define ADMIN_PRIV 0
#define STANDARD_PRIV 1
#define NUM_USERS 5
int privileges[NUM_USERS];
void initializePrivileges() {
// Gefixt: Alle Elemente explizit initialisieren
for (int i = 0; i < NUM_USERS; i++) {
privileges[i] = STANDARD_PRIV;
}
// Alle Elemente ordnungsgemäß initialisiert
}
// Gefixt: Sicherheitsoperationen werden immer ausgeführt
int isValidRequest = 0;
int isAuthenticated = 0;
int auditLogged = 0;
void processRequest(int requestType, int userId) {
// Gefixt: Audit-Logging erfolgt immer zuerst
auditLogged = logRequest(userId);
if (requestType == FAST_PATH || auditLogged) {
processData();
}
}
// Gefixt: Berechtigungsprüfung wird immer durchgeführt
void accessResource(int urgentMode, int userId) {
// Gefixt: Immer Berechtigung prüfen, urgentMode nur für Priorität verwenden
int hasPermission = checkPermission(userId);
if (hasPermission) {
if (urgentMode) {
readSensitiveDataUrgent();
} else {
readSensitiveData();
}
}
}
// Gefixt: Zähler wird immer aktualisiert
public class RateLimiter {
private int requestCount = 0;
private static final int MAX_REQUESTS = 100;
private boolean bypassEnabled = false;
public boolean allowRequest() {
// Gefixt: Zähler immer inkrementieren
requestCount++;
// Dann Limits prüfen
if (bypassEnabled || requestCount <= MAX_REQUESTS) {
return true;
}
return false;
}
public int getRequestCount() {
return requestCount; // Immer korrekt
}
}
Erkennungsmethoden
- Automatisierte statische Analyse: SAST-Tools können Nebeneffekte in bedingten Ausdrücken erkennen, insbesondere Zuweisungen und Inkrement/Dekrement-Operatoren.
- Code-Review: Suchen Sie nach Funktionsaufrufen, Zuweisungen und Operatoren mit Nebeneffekten in && und || Bedingungen.
Referenzen
- MITRE Corporation. "CWE-768: Incorrect Short Circuit Evaluation." https://cwe.mitre.org/data/definitions/768.html
- CERT C Coding Standard. "EXP02-C. Be aware of the short-circuit behavior of the logical AND and OR operators."
- CERT C++ Coding Standard. "EXP02-CPP. Be aware of the short-circuit behavior of logical expressions."