Unsachgemäße Behandlung von außergewöhnlichen Bedingungen
Beschreibung
Unsachgemäße Behandlung von außergewöhnlichen Bedingungen ist eine Schwachstelle, bei der Software eine außergewöhnliche Bedingung, die während des Betriebs auftritt, nicht behandelt oder falsch behandelt. Dies unterscheidet sich von der unsachgemäßen Prüfung (CWE-754) dadurch, dass die Bedingung erkannt wird, aber die Reaktion unzureichend ist - wie das Ignorieren des Fehlers, das Abfangen von Ausnahmen ohne korrigierende Maßnahmen oder das unangemessene Weitergeben von Ausnahmen. Wenn außergewöhnliche Bedingungen unsachgemäß behandelt werden, können Anwendungen abstürzen, in inkonsistente Zustände geraten, sensible Informationen preisgeben oder mit beschädigten Daten weiterarbeiten.
Risiko
Unsachgemäße Ausnahmebehandlung schafft mehrere Sicherheitsrisiken. Das stille Verschlucken von Ausnahmen verbirgt schwerwiegende Fehler, die Operationen beenden sollten. Das Abfangen zu breiter Ausnahmen (wie Exception anstelle spezifischer Typen) kann kritische Sicherheitsprobleme maskieren. Nicht abgefangene Ausnahmen, die bis zu den Benutzern durchdringen, können Stack-Traces preisgeben, die die interne Architektur offenlegen. Ausnahmen, die Ressourcen nicht ordnungsgemäß bereinigen, können Speicherlecks verursachen oder Locks gehalten lassen. Anwendungen, die nach Fehlern weiterlaufen, arbeiten möglicherweise mit beschädigten Daten, was zu Datenintegritätsproblemen oder ausnutzbaren Bedingungen führt. In Serverumgebungen können unbehandelte Ausnahmen ganze Dienste zum Absturz bringen.
Lösung
Behandeln Sie Ausnahmen auf der angemessenen Ebene mit spezifischen Ausnahmetypen. Fangen Sie keine Ausnahmen ab, ohne korrigierende Maßnahmen zu ergreifen - entweder das Problem beheben, protokollieren oder mit Kontext erneut werfen. Verwenden Sie finally-Blöcke oder try-with-resources, um sicherzustellen, dass Bereinigung erfolgt. Setzen Sie Ausnahmedetails nicht Endbenutzern aus; protokollieren Sie vollständige Details intern und zeigen Sie generische Meldungen extern. Entwerfen Sie Fail-Safe-Verhaltensweisen für nicht behebbare Fehler. Testen Sie Ausnahmebehandlungspfade spezifisch. Erwägen Sie die Verwendung von geprüften Ausnahmen in Sprachen, die sie unterstützen, um die Behandlung erwarteter Fehlerbedingungen zu erzwingen.
Häufige Auswirkungen
| Auswirkung | Details |
|---|---|
| Verfügbarkeit | Bereich: Verfügbarkeit DoS: Absturz, Beenden oder Neustart - Unbehandelte Ausnahmen verursachen typischerweise Anwendungsabstürze. |
| Vertraulichkeit | Bereich: Vertraulichkeit Anwendungsdaten lesen - Stack-Traces in Fehlermeldungen können sensible Implementierungsdetails offenlegen. |
| Integrität | Bereich: Integrität Unerwarteter Zustand - Unsachgemäß behandelte Fehler können Anwendungen in inkonsistenten Zuständen belassen. |
Beispielcode + Lösungscode
Anfälliger Code
// Anfällig: Nicht abgefangene Ausnahme lässt Servlet abstürzen
import javax.servlet.http.*;
import java.io.*;
public class VulnerableServlet extends HttpServlet {
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse res)
throws IOException {
String ip = req.getRemoteAddr();
// Anfällig: DNS-Lookup kann UnknownHostException werfen
// die nach oben propagiert und das Servlet abstürzen lässt
InetAddress addr = InetAddress.getByName(ip);
PrintWriter out = res.getWriter();
out.println("Hallo " + addr.getHostName());
}
}
// Anfällig: Ausnahme erkannt aber ignoriert
#include <stdlib.h>
void vulnerable_ignored_error() {
char* foo = malloc(sizeof(char));
if (foo == NULL) {
// Anfällig: Fehler erkannt aber nichts getan!
// Ausführung setzt sich mit NULL-Pointer fort
}
// Absturz oder undefiniertes Verhalten
*foo = 'a';
}
// Anfällig: Teilweise Fehlerbehandlung
int vulnerable_partial_handle(char* filename) {
FILE* f = fopen(filename, "r");
if (f == NULL) {
// Fehler protokolliert aber Funktion läuft weiter!
printf("Warnung: Konnte Datei nicht öffnen\n");
}
// Anfällig: Verwendet f auch wenn fopen fehlschlug
char buffer[100];
fgets(buffer, 100, f); // Absturz wenn f NULL ist
return 0;
}
// Anfällig: Ausnahme ohne Aktion abfangen
public class VulnerableEmptyCatch {
public void vulnerableProcess(String data) {
try {
mysteryMethod(data);
} catch (NullPointerException npe) {
// Anfällig: Ausnahme still verschluckt
// Aufrufer hat keine Ahnung, dass etwas schief ging
}
}
// Anfällig: Zu breites Exception-Catch
public void vulnerableBroadCatch() {
try {
performSecurityCheck();
processData();
} catch (Exception e) {
// Anfällig: Fängt ALLE Ausnahmen einschließlich Sicherheitsfehler
// Sicherheitsprüfungsfehler wird still ignoriert
System.out.println("Etwas ist schief gelaufen");
}
// Läuft weiter auch wenn Sicherheitsprüfung Ausnahme warf!
performSensitiveOperation();
}
}
// Anfällig: Ausnahme legt sensible Informationen offen
public void vulnerableExposure(HttpServletRequest request,
HttpServletResponse response) {
try {
String userId = request.getParameter("id");
User user = database.query("SELECT * FROM users WHERE id = " + userId);
} catch (SQLException e) {
// Anfällig: Legt Datenbankschema und Abfrage dem Benutzer offen
response.getWriter().println("Fehler: " + e.getMessage());
e.printStackTrace(response.getWriter());
}
}
# Anfällig: Ausnahmen abfangen und ignorieren
def vulnerable_ignore():
try:
result = risky_operation()
except:
pass # Anfällig: Alle Ausnahmen still ignoriert
# result kann undefiniert sein
return process(result) # NameError oder verwendet veraltete Daten
# Anfällig: Breites Exception-Catching
def vulnerable_broad_catch():
try:
authenticate_user()
perform_action()
except Exception:
# Anfällig: Authentifizierungsfehler wird abgefangen und ignoriert
print("Ein Fehler ist aufgetreten")
# Läuft ohne ordentliche Authentifizierung weiter!
return sensitive_data()
# Anfällig: Ressourcenleck bei Ausnahme
def vulnerable_resource_leak(filename):
f = open(filename, 'r') # Datei geöffnet
try:
data = f.read()
process(data) # Kann Ausnahme werfen
except:
print("Fehler bei Dateiverarbeitung")
# Anfällig: Datei wird nicht geschlossen wenn Ausnahme auftritt
f.close() # Wird nie erreicht wenn process() wirft
Behobener Code
// Behoben: Ordentliche Ausnahmebehandlung im Servlet
import javax.servlet.http.*;
import java.io.*;
import java.net.*;
public class SecureServlet extends HttpServlet {
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse res)
throws IOException {
String ip = req.getRemoteAddr();
PrintWriter out = res.getWriter();
try {
// Behoben: Potenzielle Ausnahme behandeln
InetAddress addr = InetAddress.getByName(ip);
out.println("Hallo " + addr.getHostName());
} catch (UnknownHostException e) {
// Behoben: Graceful behandeln, nicht abstürzen
logger.warn("DNS-Lookup fehlgeschlagen für IP: " + ip, e);
out.println("Hallo " + ip); // Fallback auf IP
}
}
}
// Behoben: Ordentliche Fehlerbehandlung
#include <stdlib.h>
int secure_malloc(char** out) {
char* foo = malloc(sizeof(char));
if (foo == NULL) {
// Behoben: Fehlerstatus zurückgeben
return -1;
}
*out = foo;
return 0;
}
// Behoben: Vollständige Fehlerbehandlung
int secure_file_read(char* filename, char* buffer, size_t size) {
FILE* f = fopen(filename, "r");
if (f == NULL) {
// Behoben: Fehler zurückgeben, nicht weiterlaufen
fprintf(stderr, "Konnte Datei nicht öffnen: %s\n", filename);
return -1;
}
if (fgets(buffer, size, f) == NULL) {
fclose(f); // Bei Fehler bereinigen
return -1;
}
fclose(f);
return 0;
}
// Behoben: Spezifische Ausnahmebehandlung mit Aktion
public class SecureExceptionHandling {
public void secureProcess(String data) throws ProcessingException {
try {
mysteryMethod(data);
} catch (NullPointerException npe) {
// Behoben: Protokollieren, einwickeln und mit Kontext erneut werfen
logger.error("Null-Daten in Prozess gefunden", npe);
throw new ProcessingException("Ungültige Daten bereitgestellt", npe);
}
}
// Behoben: Spezifische Ausnahmebehandlung
public void secureSpecificCatch() throws SecurityException {
try {
performSecurityCheck();
} catch (SecurityException se) {
// Behoben: Sicherheitsfehler dürfen nicht ignoriert werden
logger.error("Sicherheitsprüfung fehlgeschlagen", se);
throw se; // Sicherheitsausnahme erneut werfen
}
try {
processData();
} catch (DataException de) {
// Behoben: Datenfehler separat behandeln
logger.warn("Datenverarbeitung fehlgeschlagen", de);
// Angemessene Wiederherstellungsaktion
}
// Erreicht hier nur wenn Sicherheitsprüfung bestanden
performSensitiveOperation();
}
// Behoben: Sichere Fehlerantwort
public void secureErrorResponse(HttpServletRequest request,
HttpServletResponse response) {
try {
String userId = request.getParameter("id");
User user = userService.findById(userId);
writeResponse(response, user);
} catch (SQLException e) {
// Behoben: Details intern protokollieren
logger.error("Datenbankfehler bei Benutzersuche", e);
// Behoben: Generische Meldung an Benutzer
response.setStatus(500);
response.getWriter().println("Ein interner Fehler ist aufgetreten. " +
"Bitte versuchen Sie es später erneut.");
}
}
}
# Behoben: Spezifische Ausnahmebehandlung
def secure_process():
try:
result = risky_operation()
except ValueError as e:
# Behoben: Spezifische Ausnahme angemessen behandeln
logging.error(f"Ungültiger Wert: {e}")
return default_value()
except IOError as e:
# Behoben: Verschiedene Behandlung für verschiedene Fehler
logging.error(f"IO-Fehler: {e}")
raise ProcessingError("Operation könnte nicht abgeschlossen werden") from e
return process(result)
# Behoben: Sicherheitsbewusste Ausnahmebehandlung
def secure_auth_aware():
try:
authenticate_user()
except AuthenticationError:
# Behoben: Authentifizierungsfehler stoppen Ausführung
raise
try:
perform_action()
except ActionError as e:
# Behoben: Nicht-Sicherheitsfehler können anders behandelt werden
logging.warning(f"Aktion fehlgeschlagen: {e}")
return error_response()
return sensitive_data()
# Behoben: Ressourcenverwaltung mit Context Manager
def secure_resource_handling(filename):
try:
with open(filename, 'r') as f: # Datei automatisch geschlossen
data = f.read()
return process(data)
except IOError as e:
logging.error(f"Dateifehler: {e}")
raise FileProcessingError(f"Konnte {filename} nicht verarbeiten") from e
# Behoben: Verwendung von finally zur Bereinigung
def secure_with_finally(resource):
acquired = False
try:
resource.acquire()
acquired = True
risky_operation()
except OperationError as e:
logging.error(f"Operation fehlgeschlagen: {e}")
raise
finally:
# Behoben: Bereinigung erfolgt immer
if acquired:
resource.release()
CVE-Beispiele
- CVE-2023-41151: OPC UA-Server nicht abgefangene Ausnahme während Socket-Schreiben verursachte Absturz.
- CVE-2021-3011: Virtueller Interrupt-Controller verwendete fatalen Fehler anstatt Fehlercode zurückzugeben.
- CVE-2008-4302: OS-Kernel-Funktionsfehler führte zu unsachgemäßer Ressourcenfreigabe.
Referenzen
- MITRE Corporation. "CWE-755: Improper Handling of Exceptional Conditions." https://cwe.mitre.org/data/definitions/755.html
- CERT Java Coding Standard. "ERR00-J. Do not suppress or ignore checked exceptions."
- OWASP. "Error Handling Cheat Sheet."