Leerer Codeblock
Beschreibung
Leerer Codeblock tritt auf, wenn Quellcode einen Block enthält, der keinen Code enthält - der Block ist leer. Dies umfasst leere Funktionsrümpfe, leere bedingte Verzweigungen (if/else), leere Schleifen, leere Ausnahmebehandler und leere synchronized-Blöcke. Leere Blöcke deuten typischerweise auf unvollständige Implementierung, versehentlich gelöschten Code oder Restcode vom Refactoring hin. Obwohl manchmal beabsichtigt, sind leere Blöcke ein Code-Smell, der oft auf einen Fehler oder fehlende Funktionalität hinweist.
Risiko
Leere Codeblöcke haben verschiedene Sicherheitsimplikationen je nach Kontext. Leere Ausnahmebehandler (Catch-Blöcke) verschlucken stillschweigend Fehler und verstecken möglicherweise Sicherheitsfehler. Leere synchronized-Blöcke bieten keine Thread-Sicherheit, obwohl sie Schutz suggerieren. Leere bedingte Verzweigungen können auf fehlende Sicherheitsprüfungen hindeuten. Leere Funktionsrümpfe lassen möglicherweise Sicherheits-Callbacks unimplementiert. Leere Schleifen können unendliche Blockaden verursachen, wenn die Abbruchbedingung nie erfüllt wird. Das täuschende Erscheinungsbild funktionalen Codes führt Code-Reviewer in die Irre und lässt sie glauben, dass Sicherheitskontrollen existieren, wenn sie es nicht tun.
Lösung
Überprüfen Sie alle leeren Codeblöcke auf Absicht. Wenn beabsichtigt, fügen Sie einen Kommentar hinzu, der erklärt warum der Block leer ist. Wenn unbeabsichtigt, implementieren Sie die fehlende Funktionalität. Verwenden Sie statische Analysetools, um leere Blöcke zu erkennen. Für Ausnahmebehandler protokollieren Sie zumindest die Ausnahme. Für synchronized-Blöcke entfernen Sie sie wenn unnötig oder implementieren Sie ordnungsgemäße Synchronisation. Erwägen Sie die Verwendung von TODO-Kommentaren oder Assertions, um unvollständige Implementierungen zu markieren. Etablieren Sie Coding-Standards, die Begründung für leere Blöcke erfordern.
Häufige Auswirkungen
| Auswirkung | Details |
|---|---|
| Andere | Bereich: Ändere Reduzierte Zuverlässigkeit - Leere Blöcke können auf fehlende Funktionalität hindeuten, die das Systemverhalten beeinflusst. |
| Andere | Bereich: Ändere Variiert je nach Kontext - Auswirkung hängt davon ab, was der leere Block hätte enthalten sollen. |
| Integrität | Bereich: Integrität Unerwarteter Zustand - Leere Handler können das System nach Fehlern in ungültigen Zuständen belassen. |
Beispielcode
Anfälliger Code
// Anfällig: Verschiedene leere Codeblöcke
public class VulnerableProcessor {
// Anfällig: Leerer Methodenrumpf
public void validateInput(String input) {
// Fehlende Validierungsimplementierung!
}
// Anfällig: Leerer Ausnahmebehandler
public void processData(String data) {
try {
riskyOperation(data);
} catch (Exception e) {
// Leerer Catch - Ausnahme stillschweigend ignoriert!
}
}
// Anfällig: Leerer synchronized-Block
private int counter = 0;
public void incrementCounter() {
synchronized (this) {
// Leerer sync-Block bietet keinen Schutz!
}
counter++; // Dies ist immer noch ungeschützt!
}
// Anfällig: Leere if/else-Verzweigungen
public void handleRequest(Request request) {
if (request.isAuthenticated()) {
// Sollte authentifizierte Anfragen verarbeiten
} else {
// Sollte unauthentifizierte behandeln - tut nichts!
}
}
// Anfällig: Leerer Schleifenrumpf
public void waitForCondition() {
while (!condition) {
// Leere Schleife - potenzieller CPU-Spin/Endlosschleife
}
}
// Anfällig: Leerer finally-Block
public void cleanupResources() {
try {
allocateResource();
} finally {
// Bereinigungscode fehlt!
}
}
}
# Anfällig: Leere Codeblöcke in Python
class VulnerableService:
def validate_credentials(self, username, password):
"""Sollte Benutzer-Credentials validieren"""
pass # Leere Implementierung!
def process_payment(self, amount):
try:
charge_card(amount)
except PaymentError:
pass # Zahlungsfehler stillschweigend ignoriert!
except Exception:
pass # Alle Fehler ignoriert!
def handle_security_event(self, event):
if event.severity == 'CRITICAL':
pass # Kritische Ereignisse ignoriert!
elif event.severity == 'HIGH':
pass # Hoher Schweregrad ignoriert!
else:
pass # Alles ignoriert!
def acquire_lock(self):
with self._lock:
pass # Leerer Context-Manager - kein geschützter Code!
self._shared_data += 1 # Ungeschützt!
// Anfällig: Leere Codeblöcke in C#
public class VulnerableHandler
{
// Anfällig: Leere Methode
public virtual void OnSecurityEvent(SecurityEvent evt)
{
// Unterklasse vergisst möglicherweise zu überschreiben - Ereignis verloren!
}
// Anfällig: Leerer Catch
public void SaveData(object data)
{
try
{
_database.Save(data);
}
catch (SqlException)
{
// Datenbankfehler stillschweigend ignoriert!
}
}
// Anfällig: Leerer lock-Block
private readonly object _lockObj = new object();
private int _value;
public void UpdateValue(int newValue)
{
lock (_lockObj)
{
// Leerer lock - bietet keinen Schutz!
}
_value = newValue; // Immer noch ungeschützt!
}
// Anfällig: Leere Bedingung
public void ProcessInput(string input)
{
if (IsMalicious(input))
{
// Sollte bösartige Eingabe blockieren - tut nichts!
}
// Verarbeitet weiter potenziell bösartige Eingabe
ExecuteCommand(input);
}
}
Korrigierter Code
// Korrigiert: Ordnungsgemäße Implementierung von Codeblöcken
public class FixedProcessor {
private static final Logger logger = LoggerFactory.getLogger(FixedProcessor.class);
// Korrigiert: Implementierte Validierung
public void validateInput(String input) throws ValidationException {
if (input == null || input.trim().isEmpty()) {
throw new ValidationException("Eingabe darf nicht null oder leer sein");
}
if (input.contains("<script>")) {
throw new ValidationException("Potenzielles XSS erkannt");
}
// Zusätzliche Validierung...
}
// Korrigiert: Ordnungsgemäße Ausnahmebehandlung
public void processData(String data) throws ProcessingException {
try {
riskyOperation(data);
} catch (IOException e) {
logger.error("IO-Fehler bei Datenverarbeitung", e);
throw new ProcessingException("Datenverarbeitung fehlgeschlagen", e);
} catch (Exception e) {
logger.error("Unerwarteter Fehler bei Datenverarbeitung", e);
throw new ProcessingException("Verarbeitung fehlgeschlagen", e);
}
}
// Korrigiert: Synchronized-Block enthält geschützten Code
private int counter = 0;
public void incrementCounter() {
synchronized (this) {
counter++; // Durch Synchronisation geschützt
}
}
// Korrigiert: Implementierte bedingte Verzweigungen
public void handleRequest(Request request) throws SecurityException {
if (request.isAuthenticated()) {
processAuthenticatedRequest(request);
} else {
logger.warn("Unauthentifizierter Anfragversuch von {}",
request.getRemoteAddr());
throw new SecurityException("Authentifizierung erforderlich");
}
}
// Korrigiert: Schleife hat ordnungsgemäßen Rumpf
public void waitForCondition() throws TimeoutException {
long startTime = System.currentTimeMillis();
long timeout = 30000;
while (!condition) {
// Korrigiert: Ordnungsgemäßes Warten mit Timeout
if (System.currentTimeMillis() - startTime > timeout) {
throw new TimeoutException("Bedingung nicht innerhalb Timeout erfüllt");
}
try {
Thread.sleep(100); // CPU-Spin vermeiden
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
throw new TimeoutException("Warten unterbrochen");
}
}
}
// Korrigiert: Finally-Block führt Bereinigung durch
private Resource resource;
public void cleanupResources() {
try {
resource = allocateResource();
useResource(resource);
} finally {
if (resource != null) {
try {
resource.close();
} catch (Exception e) {
logger.warn("Fehler beim Schließen der Ressource", e);
}
}
}
}
// Korrigiert: Absichtlich leerer Block mit Dokumentation
@SuppressWarnings("EmptyBlock")
public void optionalCallback(Event event) {
if (event.getType() == EventType.DEBUG) {
// Absichtlich in Produktion ignoriert - Debug-Ereignisse sind nur für Entwicklung
// Siehe Ticket PROJ-1234 für Begründung
} else {
processEvent(event);
}
}
}
# Korrigiert: Ordnungsgemäße Implementierung in Python
import logging
logger = logging.getLogger(__name__)
class FixedService:
def validate_credentials(self, username: str, password: str) -> bool:
"""Benutzer-Credentials gegen gespeicherten Hash validieren."""
if not username or not password:
logger.warning("Leere Credentials bereitgestellt")
return False
user = self._get_user(username)
if not user:
logger.warning(f"Benutzer nicht gefunden: {username}")
return False
return self._verify_password(password, user.password_hash)
def process_payment(self, amount: float) -> PaymentResult:
"""Zahlung mit ordnungsgemäßer Fehlerbehandlung verarbeiten."""
try:
result = charge_card(amount)
logger.info(f"Zahlung verarbeitet: {amount}")
return result
except PaymentError as e:
logger.error(f"Zahlung fehlgeschlagen: {e}")
raise PaymentProcessingError(f"Zahlung von {amount} fehlgeschlagen") from e
except Exception as e:
logger.exception("Unerwarteter Zahlungsfehler")
raise PaymentProcessingError("Zahlungsverarbeitung nicht verfügbar") from e
def handle_security_event(self, event: SecurityEvent) -> None:
"""Sicherheitsereignisse basierend auf Schweregrad behandeln."""
if event.severity == 'CRITICAL':
logger.critical(f"KRITISCHES Sicherheitsereignis: {event}")
self._alert_security_team(event)
self._trigger_incident_response(event)
elif event.severity == 'HIGH':
logger.error(f"Sicherheitsereignis mit hohem Schweregrad: {event}")
self._alert_security_team(event)
else:
logger.warning(f"Sicherheitsereignis: {event}")
self._log_security_event(event)
def acquire_lock(self) -> None:
"""Thread-sichere Aktualisierung mit ordnungsgemäßer Sperrung."""
with self._lock:
# Korrigiert: Geschützter Code innerhalb des Context-Managers
self._shared_data += 1
self._last_updated = datetime.now()
# Korrigiert: Abstrakte Methode für erforderliche Implementierung
from abc import ABC, abstractmethod
class SecurityHandler(ABC):
@abstractmethod
def on_security_event(self, event: SecurityEvent) -> None:
"""Unterklassen Müssen diese Methode implementieren."""
pass # Dieses 'pass' ist in Ordnung - es ist abstrakt
// Korrigiert: Ordnungsgemäße Implementierung in C#
public class FixedHandler
{
private readonly ILogger<FixedHandler> _logger;
// Korrigiert: Abstrakte Methode erzwingt Implementierung
public abstract void OnSecurityEvent(SecurityEvent evt);
// Oder: Implementierte virtuelle Methode mit Standardverhalten
public virtual void OnSecurityEventWithDefault(SecurityEvent evt)
{
_logger.LogWarning("Sicherheitsereignis empfangen: {Event}", evt);
// Standardbehandlung die Unterklassen erweitern können
}
// Korrigiert: Ordnungsgemäße Ausnahmebehandlung
public void SaveData(object data)
{
try
{
_database.Save(data);
_logger.LogInformation("Daten erfolgreich gespeichert");
}
catch (SqlException ex)
{
_logger.LogError(ex, "Datenbankfehler beim Speichern");
throw new DataPersistenceException("Speichern der Daten fehlgeschlagen", ex);
}
}
// Korrigiert: Lock-Block enthält geschützten Code
private readonly object _lockObj = new object();
private int _value;
public void UpdateValue(int newValue)
{
lock (_lockObj)
{
// Korrigiert: Geschützter Code innerhalb lock
_value = newValue;
_lastUpdated = DateTime.UtcNow;
}
}
// Korrigiert: Bedingte Blöcke implementiert
public void ProcessInput(string input)
{
if (IsMalicious(input))
{
_logger.LogWarning("Bösartige Eingabe blockiert: {Input}", input);
throw new SecurityException("Bösartige Eingabe erkannt");
}
// Nur für nicht-bösartige Eingabe erreicht
ExecuteCommand(input);
}
}
CVE-Beispiele
Leere Codeblöcke, insbesondere leere Catch-Blöcke, haben zu zahlreichen Schwachstellen beigetragen, indem sie sicherheitsrelevante Ausnahmen stillschweigend ignorierten. Spezifische CVEs werden jedoch typischerweise auf die resultierende Schwäche abgebildet und nicht direkt auf diese CWE.
Verwandte CWEs
- CWE-1164: Irrelevant Code (Eltern)
- CWE-1069: Empty Exception Block (Kind)
- CWE-390: Detection of Error Condition Without Action (verwandt)
Referenzen
-
MITRE Corporation. "CWE-1071: Empty Code Block." https://cwe.mitre.org/data/definitions/1071.html
-
SonarSource. "Code Smell: Empty Block."
-
PMD. "Empty Statement Rules."