Übermäßig komplexe Datenrepräsentation
Beschreibung
Übermäßig komplexe Datenrepräsentation tritt auf, wenn ein Produkt eine unnötig komplexe interne Repräsentation für seine Datenstrukturen oder die Beziehungen zwischen diesen Strukturen verwendet. Dies umfasst übermäßig tiefe Vererbungshierarchien, exzessive Aggregation von nicht-primitiven Elementen, zu viele Kindklassen oder verworrene Datenmodelle, die schwer zu verstehen und zu warten sind. Während etwas Komplexität notwendig ist, macht übermäßige Komplexität die Codebasis schwerer zu analysieren, zu testen und zu sichern.
Risiko
Übermäßig komplexe Datenrepräsentationen haben indirekte Sicherheitsimplikationen. Komplexe Strukturen sind schwerer zu verstehen, was Sicherheitsanalyse schwieriger macht. Fehler einschließlich Sicherheitsschwachstellen sind in komplexem Code wahrscheinlicher. Testabdeckung ist mit komplexen Beziehungen schwerer zu erreichen. Sicherheitsprüfer können Schwachstellen in verworrenen Datenmodellen übersehen. Serialisierung und Deserialisierung komplexer Strukturen kann Schwachstellen einführen. Komplexe Vererbung kann zu unerwartetem Verhalten durch Methodenüberladungsketten führen. Leistungsverschlechterung durch komplexe Strukturen kann Denial-of-Service-Bedingungen schaffen.
Lösung
Bevorzugen Sie Komposition über Vererbung, um Hierarchietiefe zu reduzieren. Halten Sie Datenstrukturen so einfach wie möglich, während Anforderungen erfüllt werden. Wenden Sie das KISS-Prinzip (Keep It Simple, Stupid) auf Datenmodellierung an. Begrenzen Sie Vererbungstiefe (CISQ empfiehlt maximal 5 Ebenen). Begrenzen Sie die Anzahl von Kindklassen, die eine einzelne Elternklasse erweitern. Vermeiden Sie tiefe Aggregation komplexer Objekte. Verwenden Sie Entwurfsmuster angemessen, um Komplexität zu verwalten. Refaktorisieren Sie komplexe Datenmodelle in einfachere, fokussiertere Strukturen. Wenden Sie statische Analyse an, um übermäßig komplexe Strukturen zu identifizieren. Dokumentieren Sie Datenbeziehungen klar, wenn Komplexität notwendig ist.
Häufige Auswirkungen
| Auswirkung | Details |
|---|---|
| Andere | Bereich: Ändere Reduzierte Wartbarkeit - Komplexe Datenstrukturen sind schwerer zu verstehen und sicher zu ändern. |
| Andere | Bereich: Ändere Erhöhte analytische Komplexität - Sicherheitsanalyse ist mit verworrenen Datenmodellen schwieriger. |
| Verfügbarkeit | Bereich: Verfügbarkeit Reduzierte Leistung - Komplexe Strukturen können die Leistung verschlechtern. |
Beispielcode
Anfälliger Code
// Anfällig: Übermäßig tiefe Vererbungshierarchie
public class VulnerableEntity {
protected int id;
}
public class VulnerablePerson extends VulnerableEntity {
protected String name;
}
public class VulnerableEmployee extends VulnerablePerson {
protected String employeeId;
}
public class VulnerableSalariedEmployee extends VulnerableEmployee {
protected double salary;
}
public class VulnerableManager extends VulnerableSalariedEmployee {
protected List<Employee> directReports;
}
public class VulnerableSeniorManager extends VulnerableManager {
protected double bonus;
}
public class VulnerableDirector extends VulnerableSeniorManager {
protected String department;
}
public class VulnerableVicePresident extends VulnerableDirector {
protected List<String> divisions;
}
public class VulnerableExecutive extends VulnerableVicePresident {
protected double stockOptions;
}
// 9 Ebenen der Vererbung! Extrem schwer:
// - Zu verstehen, welche Felder auf jeder Ebene existieren
// - Zu wissen, welche Methoden wo überschrieben werden
// - Alle Pfade durch die Hierarchie zu testen
// - Sicherzustellen, dass Sicherheitskontrollen auf allen Ebenen korrekt angewendet werden
# Anfällig: Übermäßig komplexe Datenstruktur mit tiefer Verschachtelung
class VulnerableComplexConfig:
def __init__(self):
# Anfällig: Tief verschachtelte, komplexe Struktur
self.config = {
'system': {
'security': {
'authentication': {
'providers': {
'ldap': {
'servers': {
'primary': {
'connection': {
'ssl': {
'certificates': {
'client': {
'path': None,
'password': None # 12 Ebenen tief!
}
}
}
}
}
}
}
}
}
}
}
}
def get_cert_password(self):
# Anfällig: Zugriff auf tief verschachtelte Daten ist fehleranfällig
return (self.config
.get('system', {})
.get('security', {})
.get('authentication', {})
.get('providers', {})
.get('ldap', {})
.get('servers', {})
.get('primary', {})
.get('connection', {})
.get('ssl', {})
.get('certificates', {})
.get('client', {})
.get('password')) # Leicht Fehler zu machen!
# Anfällig: Klasse mit zu vielen aggregierten komplexen Typen
class VulnerableOrderSystem:
def __init__(self):
# Aggregiert zu viele komplexe Objekte
self.customer_manager = CustomerManager()
self.product_catalog = ProductCatalog()
self.inventory_system = InventorySystem()
self.pricing_engine = PricingEngine()
self.discount_calculator = DiscountCalculator()
self.tax_calculator = TaxCalculator()
self.shipping_calculator = ShippingCalculator()
self.payment_processor = PaymentProcessor()
self.fraud_detector = FraudDetector()
self.notification_service = NotificationService()
self.audit_logger = AuditLogger()
self.analytics_tracker = AnalyticsTracker()
self.recommendation_engine = RecommendationEngine()
self.loyalty_program = LoyaltyProgram()
self.return_handler = ReturnHandler()
# 15+ komplexe Abhängigkeiten - God-Object-Antipattern!
def process_order(self, order):
# Methode wird unmöglich komplex
# Testen erfordert Mocking von 15+ Abhängigkeiten
# Sicherheitsprüfung ist extrem schwierig
pass
// Anfällig: Komplexe Vererbung mit mehreren Pfaden
public class VulnerableShape { }
public class Vulnerable2DShape : VulnerableShape { }
public class Vulnerable3DShape : VulnerableShape { }
public class VulnerablePolygon : Vulnerable2DShape { }
public class VulnerableCurve : Vulnerable2DShape { }
public class VulnerablePolyhedron : Vulnerable3DShape { }
public class VulnerableRegularPolygon : VulnerablePolygon { }
public class VulnerableIrregularPolygon : VulnerablePolygon { }
public class VulnerableOpenCurve : VulnerableCurve { }
public class VulnerableClosedCurve : VulnerableCurve { }
public class VulnerableTriangle : VulnerableRegularPolygon { }
public class VulnerableSquare : VulnerableRegularPolygon { }
public class VulnerablePentagon : VulnerableRegularPolygon { }
public class VulnerableHexagon : VulnerableRegularPolygon { }
public class VulnerableEquilateralTriangle : VulnerableTriangle { }
public class VulnerableIsoscelesTriangle : VulnerableTriangle { }
public class VulnerableRightTriangle : VulnerableTriangle { }
public class VulnerableScaleneTriangle : VulnerableTriangle { }
// 17+ Klassen in dieser Hierarchie, 6 Ebenen tief
// Änderungen an VulnerableShape wirken sich auf alles aus
// Schwer, konsistentes Verhalten über alle Typen sicherzustellen
Korrigierter Code
// Korrigiert: Flaches, kompositionsbasiertes Design
// Verwende Komposition anstelle tiefer Vererbung
public class FixedEmployee {
private final String id;
private final PersonInfo personalInfo;
private final EmploymentDetails employment;
private final CompensationPackage compensation;
private final ManagementRole managementRole; // null wenn kein Manager
public FixedEmployee(String id, PersonInfo info, EmploymentDetails employment,
CompensationPackage compensation, ManagementRole role) {
this.id = id;
this.personalInfo = info;
this.employment = employment;
this.compensation = compensation;
this.managementRole = role;
}
public boolean isManager() {
return managementRole != null;
}
public List<FixedEmployee> getDirectReports() {
return managementRole != null ?
managementRole.getDirectReports() :
Collections.emptyList();
}
}
// Einfache, fokussierte Datenklassen
public record PersonInfo(String name, String email, LocalDate birthDate) {}
public record EmploymentDetails(
String employeeId,
LocalDate hireDate,
String department,
EmployeeLevel level
) {}
public record CompensationPackage(
Money baseSalary,
Money bonus,
StockGrant stockOptions
) {}
public record ManagementRole(
List<FixedEmployee> directReports,
List<String> managedDivisions
) {}
public enum EmployeeLevel {
INDIVIDUAL_CONTRIBUTOR,
MANAGER,
SENIOR_MANAGER,
DIRECTOR,
VP,
EXECUTIVE
}
// Vorteile:
// - Keine tiefe Vererbung - nur 1 Ebene
// - Einfach zu verstehendes Datenmodell
// - Einfach jede Komponente unabhängig zu testen
// - Sicherheitsprüfung ist unkompliziert
// - Änderungen sind auf spezifische Records lokalisiert
# Korrigiert: Flache, gut organisierte Konfiguration
from dataclasses import dataclass
from typing import Optional
@dataclass
class SSLConfig:
cert_path: str
key_path: str
password: Optional[str] = None
verify: bool = True
@dataclass
class LDAPServerConfig:
host: str
port: int = 389
use_ssl: bool = True
ssl: Optional[SSLConfig] = None
@dataclass
class LDAPConfig:
primary_server: LDAPServerConfig
fallback_server: Optional[LDAPServerConfig] = None
bind_dn: str = ""
search_base: str = ""
@dataclass
class AuthConfig:
ldap: Optional[LDAPConfig] = None
oauth_enabled: bool = False
session_timeout_minutes: int = 30
@dataclass
class SecurityConfig:
auth: AuthConfig
encryption_key_path: str
audit_enabled: bool = True
@dataclass
class SystemConfig:
security: SecurityConfig
log_level: str = "INFO"
# Korrigiert: Flacher Zugriff auf Konfiguration
class FixedConfig:
def __init__(self, config: SystemConfig):
self._config = config
@property
def ldap_ssl_password(self) -> Optional[str]:
"""Direkter, klarer Zugriffspfad."""
ldap = self._config.security.auth.ldap
if ldap and ldap.primary_server.ssl:
return ldap.primary_server.ssl.password
return None
# Korrigiert: Fokussierter Service mit begrenzten Abhängigkeiten
class FixedOrderService:
"""Bestellservice mit minimalen, fokussierten Abhängigkeiten."""
def __init__(
self,
order_repository: OrderRepository,
pricing: PricingService,
inventory: InventoryService,
events: EventPublisher
):
self._orders = order_repository
self._pricing = pricing
self._inventory = inventory
self._events = events
def create_order(self, items: List[OrderItem], customer_id: str) -> Order:
# Summe mit Preisservice berechnen
total = self._pricing.calculate(items)
# Bestand prüfen und reservieren
self._inventory.reserve(items)
# Bestellung erstellen und speichern
order = Order(
id=generate_id(),
customer_id=customer_id,
items=items,
total=total
)
self._orders.save(order)
# Event für andere Services veröffentlichen
self._events.publish(OrderCreated(order))
return order
# Andere Belange (Zahlung, Versand, Benachrichtigungen) werden von
# separaten Services gehandhabt, die Events abonnieren
# Dies folgt dem Single-Responsibility-Prinzip
// Korrigiert: Interface-basiertes Design anstelle tiefer Vererbung
// Fähigkeiten durch Interfaces definieren
public interface IShape
{
double Area { get; }
double Perimeter { get; }
}
public interface I2DShape : IShape
{
Point[] Vertices { get; }
}
public interface I3DShape : IShape
{
double Volume { get; }
double SurfaceArea { get; }
}
public interface IRegularPolygon : I2DShape
{
int Sides { get; }
double SideLength { get; }
}
// Flache Implementierungen - keine tiefe Vererbung
public sealed class Triangle : I2DShape
{
public Point A { get; }
public Point B { get; }
public Point C { get; }
public Triangle(Point a, Point b, Point c)
{
A = a;
B = b;
C = c;
}
public Point[] Vertices => new[] { A, B, C };
public double Area => Math.Abs(
(B.X - A.X) * (C.Y - A.Y) - (C.X - A.X) * (B.Y - A.Y)
) / 2;
public double Perimeter =>
Distance(A, B) + Distance(B, C) + Distance(C, A);
// Factory-Methoden für spezifische Dreieckstypen
public static Triangle Equilateral(Point center, double sideLength) =>
CreateRegularPolygon(center, sideLength, 3);
public static Triangle Isosceles(Point apex, double baseLength, double height) =>
// Implementierung
throw new NotImplementedException();
public static Triangle Right(Point rightAngle, double width, double height) =>
new Triangle(
rightAngle,
new Point(rightAngle.X + width, rightAngle.Y),
new Point(rightAngle.X, rightAngle.Y + height)
);
}
public sealed class RegularPolygon : IRegularPolygon
{
public int Sides { get; }
public double SideLength { get; }
public Point Center { get; }
public RegularPolygon(Point center, int sides, double sideLength)
{
if (sides < 3) throw new ArgumentException("Polygon muss mindestens 3 Seiten haben");
Center = center;
Sides = sides;
SideLength = sideLength;
}
public Point[] Vertices => CalculateVertices();
public double Area =>
(Sides * SideLength * SideLength) / (4 * Math.Tan(Math.PI / Sides));
public double Perimeter => Sides * SideLength;
// Eine Klasse behandelt alle regelmäßigen Polygone: Dreieck, Quadrat, Fünfeck, usw.
public static RegularPolygon Square(Point center, double sideLength) =>
new RegularPolygon(center, 4, sideLength);
public static RegularPolygon Pentagon(Point center, double sideLength) =>
new RegularPolygon(center, 5, sideLength);
public static RegularPolygon Hexagon(Point center, double sideLength) =>
new RegularPolygon(center, 6, sideLength);
}
// Vorteile:
// - Keine tiefe Vererbungshierarchie
// - Jede Klasse ist vollständig und versiegelt
// - Einfach jede Form unabhängig zu testen
// - Interfaces definieren Verträge klar
// - Factory-Methoden bieten benannte Konstruktoren für Klarheit
CVE-Beispiele
Diese CWE ist für CVE-Zuordnung als ERLAUBT-MIT-PrüfUNG markiert, da übermäßig komplexe Strukturen indirekt Schwachstellen durch schwer analysierbaren Code ermöglichen können.
Verwandte CWEs
- CWE-710: Improper Adherence to Coding Standards (Eltern)
- CWE-1043: Data Element Aggregating an Excessively Large Number of Non-Primitive Elements (Kind)
- CWE-1055: Multiple Inheritance from Concrete Classes (Kind)
- CWE-1074: Class with Excessively Deep Inheritance (Kind)
- CWE-1086: Class with Excessive Number of Child Classes (Kind)
Referenzen
- MITRE Corporation. "CWE-1093: Excessively Complex Data Representation." https://cwe.mitre.org/data/definitions/1093.html
- Martin, Robert C. "Clean Code" - Managing Complexity.
- Gamma et al. "Design Patterns" - Favor Composition over Inheritance.