Fehlender Handler
Beschreibung
Fehlender Handler ist eine Schwachstelle, bei der ein Handler für eine bestimmte Bedingung, ein Ereignis oder eine Ausnahme nicht verfügbar oder implementiert ist. Wenn eine Ausnahme geworfen und nicht abgefangen wird, oder wenn ein Ereignis ohne entsprechenden Handler auftritt, hat der Prozess die Gelegenheit aufgegeben zu entscheiden, ob ein bestimmter Fehler oder ein Ereignis eine Änderung der Ausführung wert ist. Dies kann zu Abstürzen, Informationsoffenlegung durch Fehlermeldungen oder undefiniertem Verhalten führen, wenn die Anwendung auf unerwartete Situationen ohne ordnungsgemäße Behandlungsmechanismen trifft.
Risiko
Fehlende Handler können zu Anwendungsabstürzen, Denial of Service und Informationsoffenlegung führen. Nicht abgefangene Ausnahmen offenbaren oft Debug-Informationen, Stack-Traces und interne Implementierungsdetails, die für Angreifer wertvoll sind. In vernetzten Anwendungen können fehlende Handler für fehlerhafte Eingaben Dienste zum Absturz bringen oder sie in undefinierte Zustände versetzen. Anwendungen ohne Handler für Ressourcenerschöpfung können ungraceful versagen. Sicherheitskritische Operationen ohne Fehler-Handler können Systeme in unsicheren Zuständen hinterlassen. Das unvorhersehbare Verhalten unbehandelter Ereignisse macht Anwendungen unzuverlässig und potenziell ausnutzbar.
Lösung
Behandeln Sie alle möglichen Situationen einschließlich Fehlerbedingungen umfassend. Wenn eine Operation eine Ausnahme werfen kann, implementieren Sie einen Handler für diesen spezifischen Ausnahmetyp. Verwenden Sie Catch-All-Handler als letzten Ausweg, um nicht abgefangene Ausnahmen zu verhindern, während Sie die unerwartete Bedingung trotzdem protokollieren. Implementieren Sie Standard-Handler für Ereignisse, die möglicherweise keine spezifischen Handler haben. Entwerfen Sie APIs so, dass explizite Behandlung von Fehlerfällen erforderlich ist. Verwenden Sie statische Analysetools, um unbehandelte Ausnahmen zu erkennen. Testen Sie mit Fuzzing, um unbehandelte Randfälle zu entdecken.
Häufige Auswirkungen
| Auswirkung | Details |
|---|---|
| Sonstiges | Umfang: Sonstiges Variiert je nach Kontext - Die Auswirkung hängt vom spezifischen Implementierungskontext ab. Nicht abgefangene Ausnahmen können Abstürze, Informationsoffenlegung durch Fehlermeldungen oder undefinierte Anwendungszustände verursachen. |
Beispielcode
Anfälliger Code
// Anfällig: Servlet ohne Ausnahmebehandlung
public class VulnerableServlet extends HttpServlet {
protected void doPost(HttpServletRequest req, HttpServletResponse res)
throws IOException {
String ip = req.getRemoteAddr();
// Anfällig: DNS-Lookup kann mit UnknownHostException fehlschlagen
// Kein Handler - Ausnahme propagiert, offenbart Debug-Infos
InetAddress addr = InetAddress.getByName(ip);
PrintWriter out = res.getWriter();
out.println("hello " + addr.getHostName());
}
}
// Wenn DNS-Lookup fehlschlägt, sieht Angreifer:
// java.net.UnknownHostException: 192.168.1.100
// at java.net.InetAddress.getByName(InetAddress.java:...)
// at VulnerableServlet.doPost(VulnerableServlet.java:10)
// ...
# Anfällig: Fehlende Handler für Dateioperationen
def vulnerable_read_config(config_path):
# Anfällig: Kein Handler für FileNotFoundError
with open(config_path, 'r') as f:
config = json.load(f) # Kein Handler für JSONDecodeError
return config
# Anfällig: Fehlender Handler für Netzwerkoperationen
def vulnerable_fetch_data(url):
# Anfällig: Kein Handler für Verbindungsfehler, Timeouts, etc.
response = requests.get(url)
return response.json() # Kein Handler für ungültiges JSON
// Anfällig: Fehlender Handler für Speicherallokationsfehler
#include <stdlib.h>
void vulnerable_process_data(size_t size) {
// Anfällig: malloc kann NULL zurückgeben
char *buffer = malloc(size);
// Anfällig: Keine NULL-Prüfung - stürzt bei Dereferenzierung ab
memset(buffer, 0, size);
process(buffer);
free(buffer);
}
// Anfällig: Fehlender Handler für Signal
void vulnerable_server() {
// Anfällig: Kein SIGPIPE-Handler - Schreiben auf geschlossenen Socket stürzt ab
while (1) {
int client = accept(server_fd, NULL, NULL);
handle_client(client);
}
}
// Anfällig: Fehlende Handler in ereignisgesteuertem Code
public class VulnerableEventHandler
{
public void ProcessMessage(string message)
{
// Anfällig: Kein Handler für null-Nachricht
var parsed = ParseMessage(message); // NullReferenceException
// Anfällig: Kein Handler für ungültiges Format
var data = ExtractData(parsed); // FormatException
// Anfällig: Kein Handler für DB-Fehler
SaveToDatabase(data); // SqlException
}
// Anfällig: Fehlender Event-Handler
public void Initialize()
{
connection.OnDisconnect += null; // Kein Handler für Disconnect-Ereignisse
// Anwendung weiß nicht, wenn Verbindung verloren geht
}
}
Korrigierter Code
// Korrigiert: Umfassende Ausnahmebehandlung
public class SecureServlet extends HttpServlet {
private static final Logger logger = LoggerFactory.getLogger(SecureServlet.class);
protected void doPost(HttpServletRequest req, HttpServletResponse res)
throws IOException {
String ip = req.getRemoteAddr();
PrintWriter out = res.getWriter();
try {
// Korrigiert: Potenziellen DNS-Fehler behandeln
InetAddress addr = InetAddress.getByName(ip);
out.println("hello " + addr.getHostName());
} catch (UnknownHostException e) {
// Korrigiert: Fehler intern protokollieren, sichere Nachricht an Benutzer zeigen
logger.warn("DNS-Lookup fehlgeschlagen für IP: {}", ip, e);
out.println("hello " + ip); // Fallback auf IP-Adresse
} catch (SecurityException e) {
// Korrigiert: Security-Manager-Einschränkungen behandeln
logger.error("Security-Ausnahme während DNS-Lookup", e);
res.sendError(HttpServletResponse.SC_FORBIDDEN, "Zugriff verweigert");
} catch (Exception e) {
// Korrigiert: Catch-All für unerwartete Ausnahmen
logger.error("Unerwarteter Fehler in doPost", e);
res.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
"Ein Fehler ist aufgetreten");
}
}
}
# Korrigiert: Umfassende Fehlerbehandlung
import json
import logging
import requests
from requests.exceptions import RequestException, Timeout, ConnectionError
logger = logging.getLogger(__name__)
def secure_read_config(config_path, default_config=None):
try:
with open(config_path, 'r') as f:
config = json.load(f)
return config
except FileNotFoundError:
# Korrigiert: Fehlende Datei behandeln
logger.warning(f"Config-Datei nicht gefunden: {config_path}")
if default_config:
return default_config
raise ConfigurationError(f"Erforderliche Config-Datei fehlt: {config_path}")
except json.JSONDecodeError as e:
# Korrigiert: Fehlerhaftes JSON behandeln
logger.error(f"Ungültiges JSON in Config-Datei: {e}")
raise ConfigurationError(f"Fehlerhafte Config-Datei: {config_path}")
except PermissionError:
# Korrigiert: Berechtigungsprobleme behandeln
logger.error(f"Berechtigung zum Lesen der Config verweigert: {config_path}")
raise ConfigurationError(f"Config-Datei kann nicht gelesen werden: {config_path}")
def secure_fetch_data(url, timeout=30, retries=3):
for attempt in range(retries):
try:
response = requests.get(url, timeout=timeout)
response.raise_for_status() # Bei 4xx/5xx werfen
return response.json()
except Timeout:
# Korrigiert: Timeout behandeln
logger.warning(f"Anfrage-Timeout (Versuch {attempt + 1}/{retries}): {url}")
if attempt == retries - 1:
raise
except ConnectionError as e:
# Korrigiert: Verbindungsfehler behandeln
logger.error(f"Verbindung fehlgeschlagen: {url} - {e}")
raise
except requests.HTTPError as e:
# Korrigiert: HTTP-Fehler behandeln
logger.error(f"HTTP-Fehler {e.response.status_code}: {url}")
raise
except json.JSONDecodeError:
# Korrigiert: Ungültige JSON-Antwort behandeln
logger.error(f"Ungültige JSON-Antwort von: {url}")
raise DataError(f"Server gab ungültiges JSON zurück")
// Korrigiert: Ordnungsgemäße Fehlerbehandlung für alle Fehlermodi
#include <stdlib.h>
#include <signal.h>
#include <errno.h>
// Korrigiert: Handler für SIGPIPE
void sigpipe_handler(int sig) {
// Protokollieren aber nicht abstürzen - write() EPIPE zurückgeben lassen
}
int secure_process_data(size_t size) {
// Korrigiert: Größe validieren
if (size == 0 || size > MAX_ALLOWED_SIZE) {
log_error("Ungültige Größe: %zu", size);
return -1;
}
// Korrigiert: malloc-Rückgabewert prüfen
char *buffer = malloc(size);
if (buffer == NULL) {
log_error("Speicherallokation fehlgeschlagen für Größe: %zu", size);
return -1;
}
memset(buffer, 0, size);
int result = process(buffer);
free(buffer);
return result;
}
int secure_server() {
// Korrigiert: Signal-Handler installieren
struct sigaction sa;
sa.sa_handler = sigpipe_handler;
sigemptyset(&sa.sa_mask);
sa.sa_flags = 0;
sigaction(SIGPIPE, &sa, NULL);
while (1) {
int client = accept(server_fd, NULL, NULL);
// Korrigiert: accept-Fehler behandeln
if (client < 0) {
if (errno == EINTR) {
continue; // Unterbrochen, erneut versuchen
}
log_error("Accept fehlgeschlagen: %s", strerror(errno));
continue; // Nicht abstürzen, weiter akzeptieren
}
// Korrigiert: Client in try-catch-Äquivalent behandeln
if (handle_client(client) < 0) {
log_error("Client-Behandlung fehlgeschlagen");
}
close(client);
}
}
// Korrigiert: Umfassende Event- und Ausnahmebehandlung
public class SecureEventHandler
{
private readonly ILogger _logger;
public void ProcessMessage(string message)
{
// Korrigiert: Eingabe validieren
if (string.IsNullOrEmpty(message))
{
_logger.LogWarning("Null- oder leere Nachricht empfangen");
return;
}
try
{
var parsed = ParseMessage(message);
var data = ExtractData(parsed);
SaveToDatabase(data);
}
catch (FormatException ex)
{
// Korrigiert: Ungültiges Format behandeln
_logger.LogError(ex, "Ungültiges Nachrichtenformat");
throw new MessageProcessingException("Ungültiges Nachrichtenformat", ex);
}
catch (SqlException ex)
{
// Korrigiert: Datenbankfehler behandeln
_logger.LogError(ex, "Datenbankfehler beim Speichern der Nachricht");
throw new MessageProcessingException("Nachricht könnte nicht gespeichert werden", ex);
}
catch (Exception ex)
{
// Korrigiert: Catch-All mit Protokollierung
_logger.LogError(ex, "Unerwarteter Fehler bei Nachrichtenverarbeitung");
throw;
}
}
public void Initialize()
{
// Korrigiert: Event-Handler installieren
connection.OnDisconnect += HandleDisconnect;
connection.OnError += HandleError;
connection.OnTimeout += HandleTimeout;
}
private void HandleDisconnect(object sender, EventArgs e)
{
_logger.LogWarning("Verbindung getrennt");
// Wiederverbindung versuchen oder aufräumen
TryReconnect();
}
private void HandleError(object sender, ErrorEventArgs e)
{
_logger.LogError(e.Exception, "Verbindungsfehler");
}
private void HandleTimeout(object sender, EventArgs e)
{
_logger.LogWarning("Verbindungs-Timeout");
}
}
CVE-Beispiele
- CVE-2022-25302 — SDK für OPC Unified Architecture (OPC UA) fehlt ein Handler für fehlgeschlagene Casts, was einen Absturz ermöglicht.
Referenzen
- MITRE Corporation. "CWE-431: Missing Handler." https://cwe.mitre.org/data/definitions/431.html
- CERT Oracle Secure Coding Standard for Java. "ERR00-J. Do not suppress or ignore checked exceptions." https://wiki.sei.cmu.edu/confluence/display/java/ERR00-J.+Do+not+suppress+or+ignore+checked+exceptions