Ü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

AuswirkungDetails
AndereBereich: Ändere

Reduzierte Wartbarkeit - Komplexe Datenstrukturen sind schwerer zu verstehen und sicher zu ändern.
AndereBereich: Ändere

Erhöhte analytische Komplexität - Sicherheitsanalyse ist mit verworrenen Datenmodellen schwieriger.
VerfügbarkeitBereich: 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

  1. MITRE Corporation. "CWE-1093: Excessively Complex Data Representation." https://cwe.mitre.org/data/definitions/1093.html
  2. Martin, Robert C. "Clean Code" - Managing Complexity.
  3. Gamma et al. "Design Patterns" - Favor Composition over Inheritance.