Aufrufbares Steuerelement mit größer Anzahl ausgehender Aufrufe

Beschreibung

Aufrufbares Steuerelement mit größer Anzahl ausgehender Aufrufe tritt auf, wenn ein aufrufbares Codeelement (Funktion, Methode, Prozedur) eine übermäßig große Anzahl von Referenzen auf andere Anwendungsobjekte außerhalb seines Kontexts enthält. Dies wird als hoher "Fan-Out"-Wert gemessen. CISQ empfiehlt, dass ein Fan-Out-Wert über 5 referenzierten Objekten als übermäßig betrachtet wird, obwohl organisatorische Standards variieren können. Hoher Fan-Out zeigt an, dass eine Funktion zu viel tut und das Single-Responsibility-Prinzip verletzt sowie enge Kopplung mit vielen anderen Komponenten erzeugt.

Risiko

Obwohl hauptsächlich ein Code-Qualitätsproblem, hat hoher Fan-Out indirekte Sicherheitsimplikationen. Funktionen mit vielen Abhängigkeiten sind: (1) schwerer zu verstehen und auf Sicherheitsschwachstellen zu überprüfen, (2) wahrscheinlicher fehlerhaft aufgrund von Komplexität, (3) schwierig umfassend zu testen, was Sicherheitsprobleme unentdeckt lässt, (4) riskant zu modifizieren, weil Änderungen unerwartete Auswirkungen auf abhängige Komponenten haben können, und (5) neigen dazu, unnötige Abhängigkeiten einzuschließen, die die Angriffsfläche erweitern.

Lösung

Refaktorisieren Sie Funktionen mit hohem Fan-Out durch: (1) Aufteilen in kleinere, fokussierte Funktionen mit klaren einzelnen Verantwortlichkeiten, (2) Gruppieren verwandter externer Aufrufe in dedizierte Service-Klassen, (3) Verwenden des Facade-Patterns zur Vereinfachung komplexer Subsystem-Interaktionen, (4) Anwenden von Dependency Injection, um Abhängigkeiten explizit und testbar zu machen, (5) Verwenden von Komposition, um Arbeit an spezialisierte Komponenten zu delegieren. Setzen Sie Code-Qualitäts-Schwellenwerte in statischen Analysetools, um hohen Fan-Out zu kennzeichnen.

Häufige Auswirkungen

AuswirkungDetails
AndereBereich: Ändere

Reduzierte Wartbarkeit - Hoher Fan-Out erzeugt enge Kopplung, die Code schwerer zu warten und zu sichern macht.
AndereBereich: Ändere

Reduzierte Zuverlässigkeit - Komplexe Funktionen mit vielen Abhängigkeiten sind anfälliger für Fehler und Sicherheitsschwachstellen.

Beispielcode

Anfälliger Code

// ANFÄLLIG: Methode mit übermäßigem Fan-Out (15+ externe Referenzen)
public class VulnerableOrderProcessor {

    public OrderResult processOrder(OrderRequest request) {
        // Fan-Out 1: CustomerService
        Customer customer = customerService.getCustomer(request.getCustomerId());

        // Fan-Out 2: ValidationService
        validationService.validateCustomer(customer);

        // Fan-Out 3: AddressService
        Address shippingAddress = addressService.getAddress(request.getAddressId());

        // Fan-Out 4: AddressValidator
        addressValidator.validate(shippingAddress);

        // Fan-Out 5: InventoryService
        inventoryService.checkAvailability(request.getItems());

        // Fan-Out 6: PricingService
        BigDecimal total = pricingService.calculateTotal(request.getItems());

        // Fan-Out 7: DiscountService
        BigDecimal discount = discountService.applyDiscounts(customer, total);

        // Fan-Out 8: TaxService
        BigDecimal tax = taxService.calculateTax(total.subtract(discount), shippingAddress);

        // Fan-Out 9: PaymentGateway
        PaymentResult payment = paymentGateway.processPayment(
            customer.getPaymentMethod(), total.add(tax));

        // Fan-Out 10: FraudService
        fraudService.checkTransaction(customer, payment);

        // Fan-Out 11-17: Weitere Services...
        orderRepository.create(customer, request.getItems(), total);
        inventoryService.reserveItems(request.getItems());
        shippingService.scheduleShipment(order, shippingAddress);
        notificationService.sendOrderConfirmation(customer, order);
        analyticsService.trackOrder(order);
        loyaltyService.awardPoints(customer, total);
        auditService.logOrderCreation(order);

        return new OrderResult(order);
    }

    // Probleme:
    // - Schwer alle Interaktionen zu verstehen
    // - Schwierig zu testen (17+ Mocks benötigt)
    // - Jede Service-Änderung kann diese Methode beeinflussen
    // - Sicherheitsaudit erfordert Verständnis aller 17 Services
}

Korrigierter Code

// KORRIGIERT: Zerlegt in fokussierte Klassen mit niedrigerem Fan-Out

// Orchestrator mit minimalem Fan-Out (3 Abhängigkeiten)
public class FixedOrderProcessor {
    private final OrderValidationService validationService;
    private final OrderFulfillmentService fulfillmentService;
    private final OrderNotificationService notificationService;

    public OrderResult processOrder(OrderRequest request) {
        // Fan-Out 1: Validierung (kapselt Validierungsbelange)
        ValidationResult validation = validationService.validate(request);
        if (!validation.isValid()) {
            return OrderResult.failed(validation.getErrors());
        }

        // Fan-Out 2: Erfüllung (kapselt Bestellerstellung)
        Order order = fulfillmentService.fulfill(request);

        // Fan-Out 3: Benachrichtigungen (kapselt Nachverarbeitung)
        notificationService.notifyOrderCreated(order);

        return OrderResult.success(order);
    }
}

// Fokussierter Validierungsservice (Fan-Out ~4-5, jeweils fokussiert)
public class OrderValidationService {
    private final CustomerValidator customerValidator;
    private final AddressValidator addressValidator;
    private final InventoryValidator inventoryValidator;
    private final PaymentValidator paymentValidator;

    public ValidationResult validate(OrderRequest request) {
        ValidationResult result = new ValidationResult();

        result.merge(customerValidator.validate(request.getCustomerId()));
        result.merge(addressValidator.validate(request.getAddressId()));
        result.merge(inventoryValidator.validate(request.getItems()));
        result.merge(paymentValidator.validate(request.getPaymentInfo()));

        return result;
    }
}

// Fokussierter Erfüllungsservice
public class OrderFulfillmentService {
    private final PricingFacade pricingFacade;
    private final PaymentFacade paymentFacade;
    private final OrderRepository orderRepository;
    private final InventoryFacade inventoryFacade;

    public Order fulfill(OrderRequest request) {
        // Preisberechnung (Facade verbirgt Komplexität)
        PricingResult pricing = pricingFacade.calculate(request);

        // Zahlung verarbeiten
        PaymentResult payment = paymentFacade.process(request, pricing.getTotal());

        // Bestellung erstellen
        Order order = orderRepository.create(request, pricing, payment);

        // Bestand reservieren
        inventoryFacade.reserve(order);

        return order;
    }
}

// Preis-Facade - kapselt Preiskomplexität
public class PricingFacade {
    private final PricingService pricingService;
    private final DiscountService discountService;
    private final TaxService taxService;

    public PricingResult calculate(OrderRequest request) {
        BigDecimal subtotal = pricingService.calculateSubtotal(request.getItems());
        BigDecimal discount = discountService.calculate(request);
        BigDecimal tax = taxService.calculate(subtotal.subtract(discount));

        return new PricingResult(subtotal, discount, tax);
    }
}
# KORRIGIERT: Zerlegte Registrierung mit handhabbarem Fan-Out

class UserRegistrationOrchestrator:
    """Orchestriert Registrierung mit niedrigem Fan-Out (3 Services)"""

    def __init__(self,
                 validation_service: RegistrationValidationService,
                 creation_service: UserCreationService,
                 post_registration_service: PostRegistrationService):
        self.validation = validation_service
        self.creation = creation_service
        self.post_registration = post_registration_service

    def register(self, request: RegistrationRequest) -> User:
        # Fan-Out 1: Validieren
        self.validation.validate(request)

        # Fan-Out 2: Benutzer erstellen
        user = self.creation.create(request)

        # Fan-Out 3: Nachregistrierungsaufgaben (asynchron)
        self.post_registration.process(user, request)

        return user


class RegistrationValidationService:
    """Fokussierter Validierungsservice (Fan-Out ~4)"""

    def __init__(self,
                 input_validator: InputValidator,
                 uniqueness_checker: UniquenessChecker,
                 captcha_verifier: CaptchaVerifier):
        self.input_validator = input_validator
        self.uniqueness_checker = uniqueness_checker
        self.captcha_verifier = captcha_verifier

    def validate(self, request: RegistrationRequest):
        self.input_validator.validate(request)
        self.uniqueness_checker.check(request.email, request.username)
        self.captcha_verifier.verify(request.captcha_token)


class UserCreationService:
    """Fokussierter Erstellungsservice (Fan-Out ~3)"""

    def __init__(self,
                 password_hasher: PasswordHasher,
                 user_factory: UserFactory,
                 user_repository: UserRepository):
        self.password_hasher = password_hasher
        self.user_factory = user_factory
        self.user_repository = user_repository

    def create(self, request: RegistrationRequest) -> User:
        password_hash = self.password_hasher.hash(request.password)
        user = self.user_factory.create(request, password_hash)
        return self.user_repository.save(user)

CVE-Beispiele

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


Verwandte CWEs

  • CWE-710: Improper Adherence to Coding Standards (Eltern)
  • CWE-1006: Bad Coding Practices (Kategoriemitglied)
  • CWE-1120: Excessive Code Complexity (verwandt)

Referenzen

  1. MITRE Corporation. "CWE-1048: Invokable Control Element with Large Number of Outward Calls." https://cwe.mitre.org/data/definitions/1048.html

  2. CISQ. "Automated Source Code Quality Measures."

  3. Martin, Robert C. "Clean Code: A Handbook of Agile Software Craftsmanship."