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
| Auswirkung | Details |
|---|---|
| Andere | Bereich: Ändere Reduzierte Wartbarkeit - Hoher Fan-Out erzeugt enge Kopplung, die Code schwerer zu warten und zu sichern macht. |
| Andere | Bereich: Ä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
-
MITRE Corporation. "CWE-1048: Invokable Control Element with Large Number of Outward Calls." https://cwe.mitre.org/data/definitions/1048.html
-
CISQ. "Automated Source Code Quality Measures."
-
Martin, Robert C. "Clean Code: A Handbook of Agile Software Craftsmanship."