Elternklasse mit Referenzen auf Kindklasse

Beschreibung

Elternklasse mit Referenzen auf Kindklasse tritt auf, wenn eine Elternklasse eine Referenz oder einen Pointer auf eine Kindklasse enthält, entweder direkt oder indirekt durch eine andere Klasse. Dies erzeugt eine zirkulare Abhängigkeit zwischen Eltern- und Kindklassen und verletzt das Prinzip der Modularität und ordnungsgemäßer Vererbungshierarchien. Eine Elternklasse sollte ihre Kinder nicht kennen, da Kinder die Eltern erweitern - nicht umgekehrt. Dieses Anti-Pattern macht die Codebasis schwerer zu warten, zu erweitern und zu testen.

Risiko

Obwohl hauptsächlich ein Code-Qualitätsproblem, erzeugt dieses Muster indirekte Sicherheitsrisiken. Die zirkulare Abhängigkeit erschwert die ordnungsgemäße Prüfung von Sicherheitskontrollen, da Änderungen in Kindklassen unerwartet das Elternverhalten beeinflussen können. Unit-Tests werden kompliziert, was möglicherweise zu inadäquater Sicherheitstestabdeckung führt. Die enge Kopplung erschwert den Austausch oder das Upgrade sicherheitskritischer Komponenten. Code-Refactoring wird riskant, und Entwickler können notwendige Sicherheitsverbesserungen wegen der Komplexität vermeiden. Das Muster verletzt auch SOLID-Prinzipien (Open/Closed, Dependency Inversion), was die Codebasis fragiler macht.

Lösung

Wenden Sie das Dependency Inversion Principle an - High-Level-Module sollten nicht von Low-Level-Modulen abhängen, beide sollten von Abstraktionen abhängen. Verwenden Sie Interfaces oder abstrakte Klassen, um Verträge zu definieren, die Kindklassen implementieren. Wenden Sie das Factory-Pattern oder Dependency Injection an, um Instanzen ohne direkte Referenzen zu erstellen. Refaktorisieren Sie gemeinsame Funktionalität, die sowohl von Eltern als auch Kind benötigt wird, in separate Hilfsklassen. Verwenden Sie ereignisgesteuerte Architekturen oder Observer-Patterns, wenn Elternklassen auf Kindklassenaktionen reagieren müssen.

Häufige Auswirkungen

AuswirkungDetails
AndereBereich: Ändere

Reduzierte Wartbarkeit - Zirkulare Abhängigkeiten machen die Codebasis schwerer zu verstehen, zu testen und sicher zu modifizieren.
AndereBereich: Ändere

Qualitätsverschlechterung - Enge Kopplung führt zu fragilem Code, wo Änderungen unerwartete Auswirkungen haben.
AndereBereich: Ändere

Reduzierte Zuverlässigkeit - Testen wird schwieriger, was möglicherweise Fehler und Schwachstellen unentdeckt lässt.

Beispielcode

Anfälliger Code

// Anfällig: Elternklasse referenziert Kindklasse direkt
public class VulnerableBaseDocument {
    protected String content;
    protected String author;

    // Anfällig: Eltern kennt spezifische Kindklasse!
    public VulnerablePDFDocument convertToPDF() {
        // Elternklasse erstellt und gibt Kindklasseninstanz zurück
        VulnerablePDFDocument pdf = new VulnerablePDFDocument();
        pdf.setContent(this.content);
        pdf.setAuthor(this.author);
        pdf.generatePDF();
        return pdf;
    }

    // Anfällig: Weitere Referenz auf Kindklasse
    public VulnerableWordDocument convertToWord() {
        VulnerableWordDocument word = new VulnerableWordDocument();
        word.setContent(this.content);
        word.setAuthor(this.author);
        return word;
    }

    // Anfällig: Typprüfung für Kindklassen
    public void process(VulnerableBaseDocument doc) {
        if (doc instanceof VulnerablePDFDocument) {
            ((VulnerablePDFDocument) doc).compress();
        } else if (doc instanceof VulnerableWordDocument) {
            ((VulnerableWordDocument) doc).applyStyles();
        }
    }
}

// Kindklassen
public class VulnerablePDFDocument extends VulnerableBaseDocument {
    public void generatePDF() { /* ... */ }
    public void compress() { /* ... */ }
}

public class VulnerableWordDocument extends VulnerableBaseDocument {
    public void applyStyles() { /* ... */ }
}

// Probleme:
// 1. Hinzufügen neuer Dokumenttypen erfordert Modifikation der Elternklasse
// 2. Elternklasse ist eng an alle Kinder gekoppelt
// 3. Verletzt Open/Closed Principle
# Anfällig: Elternklasse mit Kindklassen-Imports
class VulnerableAnimal:
    def __init__(self, name):
        self.name = name

    # Anfällig: Eltern erstellt Kindinstanzen
    def create_offspring(self, offspring_type):
        # Direkte Referenz auf Kindklassen im Eltern
        if offspring_type == "dog":
            from animals import VulnerableDog  # Zirkularer Import!
            return VulnerableDog(f"{self.name}'s Welpe")
        elif offspring_type == "cat":
            from animals import VulnerableCat  # Zirkularer Import!
            return VulnerableCat(f"{self.name}'s Kätzchen")
        else:
            raise ValueError(f"Unbekannter Typ: {offspring_type}")

    # Anfällig: Typspezifische Logik im Eltern
    def get_sound(self):
        from animals import VulnerableDog, VulnerableCat
        if isinstance(self, VulnerableDog):
            return "Wuff!"
        elif isinstance(self, VulnerableCat):
            return "Miau!"
        return "Unbekannt"

Korrigierter Code

// Korrigiert: Verwendung von Interfaces und Factory-Pattern
public abstract class FixedBaseDocument {
    protected String content;
    protected String author;

    public abstract String getFormat();

    // Korrigiert: Keine Referenzen auf Kindklassen
    // Konvertierung durch separate Konverterklassen behandelt
    public String getContent() {
        return content;
    }

    public String getAuthor() {
        return author;
    }

    public void setContent(String content) {
        this.content = content;
    }

    public void setAuthor(String author) {
        this.author = author;
    }
}

// Korrigiert: Kindklassen sind unabhängig
public class FixedPDFDocument extends FixedBaseDocument {
    @Override
    public String getFormat() {
        return "PDF";
    }

    public void generatePDF() { /* ... */ }
    public void compress() { /* ... */ }
}

public class FixedWordDocument extends FixedBaseDocument {
    @Override
    public String getFormat() {
        return "DOCX";
    }

    public void applyStyles() { /* ... */ }
}

// Korrigiert: Factory-Pattern für Dokumenterstellung
public interface DocumentFactory {
    FixedBaseDocument createDocument();
}

public class PDFDocumentFactory implements DocumentFactory {
    @Override
    public FixedBaseDocument createDocument() {
        return new FixedPDFDocument();
    }
}

// Korrigiert: Konverter-Interface für Formatkonvertierung
public interface DocumentConverter<T extends FixedBaseDocument> {
    T convert(FixedBaseDocument source);
}

public class PDFConverter implements DocumentConverter<FixedPDFDocument> {
    @Override
    public FixedPDFDocument convert(FixedBaseDocument source) {
        FixedPDFDocument pdf = new FixedPDFDocument();
        pdf.setContent(source.getContent());
        pdf.setAuthor(source.getAuthor());
        pdf.generatePDF();
        return pdf;
    }
}
# Korrigiert: Verwendung von abstrakter Basisklasse und Factory-Pattern
from abc import ABC, abstractmethod
from typing import Dict, Type, Callable


class FixedAnimal(ABC):
    def __init__(self, name: str):
        self.name = name

    @abstractmethod
    def get_sound(self) -> str:
        """Jedes Tier implementiert seinen eigenen Laut"""
        pass

    # Korrigiert: Keine Referenzen auf Kindklassen
    # Nachkommen-Erstellung an Factory delegiert


class FixedDog(FixedAnimal):
    def get_sound(self) -> str:
        return "Wuff!"

    def bark(self):
        print(self.get_sound())


class FixedCat(FixedAnimal):
    def get_sound(self) -> str:
        return "Miau!"

    def meow(self):
        print(self.get_sound())


# Korrigiert: Factory-Pattern in separatem Modul
class AnimalFactory:
    """Factory für Tiererstellung - hält Eltern unwissend über Kinder"""

    _registry: Dict[str, Type[FixedAnimal]] = {}

    @classmethod
    def register(cls, animal_type: str, animal_class: Type[FixedAnimal]):
        cls._registry[animal_type] = animal_class

    @classmethod
    def create(cls, animal_type: str, name: str) -> FixedAnimal:
        if animal_type not in cls._registry:
            raise ValueError(f"Unbekannter Tiertyp: {animal_type}")
        return cls._registry[animal_type](name)


# Registrierung geschieht im Anwendungs-Setup, nicht in Elternklasse
AnimalFactory.register("dog", FixedDog)
AnimalFactory.register("cat", FixedCat)

# Verwendung
animal = AnimalFactory.create("dog", "Bello")
print(animal.get_sound())  # "Wuff!"

CVE-Beispiele

Diese CWE ist für direkte CVE-Zuordnung als VERBOTEN markiert, da sie ein Code-Qualitäts-/Design-Problem und keine direkte Sicherheitsschwachstelle darstellt.


Verwandte CWEs

  • CWE-710: Improper Adherence to Coding Standards (Eltern)
  • CWE-1047: Circular Dependency (verwandt)
  • CWE-1055: Multiple Inheritance from Concrete Classes (verwandt)
  • CWE-1227: Encapsulation Issues (Kategoriemitglied)

Referenzen

  1. MITRE Corporation. "CWE-1062: Parent Class with References to Child Class." https://cwe.mitre.org/data/definitions/1062.html

  2. Martin, Robert C. "Clean Architecture: A Craftsman's Guide to Software Structure and Design."

  3. Gamma, Erich et al. "Design Patterns: Elements of Reusable Object-Oriented Software."