Aufrufbares Kontrollelement mit Signatur mit übermäßiger Anzahl von Parametern

Beschreibung

Aufrufbares Kontrollelement mit Signatur mit übermäßiger Anzahl von Parametern tritt auf, wenn eine Funktion oder Methode eine übermäßige Anzahl von Parametern hat, was die korrekte Verwendung und Wartung erschwert. CISQ empfiehlt einen Standardschwellenwert von maximal 7 Parametern. Funktionen mit vielen Parametern sind fehleranfällig, da Aufrufer die Parameterreihenfolge verwechseln, falsche Werte übergeben oder erforderliche Parameter vergessen können. Dieses Anti-Pattern deutet oft darauf hin, dass die Funktion zu viel tut und refaktorisiert werden sollte.

Risiko

Obwohl hauptsächlich ein Code-Qualitätsproblem, erzeugen übermäßige Parameter indirekte Sicherheitsrisiken. Parameterverwechslung kann dazu führen, dass sicherheitskritische Werte an falschen Positionen platziert werden (z.B. Vertauschen einer Benutzer-ID mit einer Berechtigungsstufe). Länge Parameterlisten erschweren Code-Reviews und können Sicherheitsprobleme übersehen. Die Komplexität entmutigt gründliches Testen und lässt Randfälle ungetestet. Funktionen mit vielen Parametern haben oft komplexe interne Logik, die Schwachstellen enthalten kann. Boolesche Parameter in langen Listen sind besonders problematisch, da ihre Bedeutung an Aufrufstellen unklar ist und möglicherweise zu Sicherheitsfehlkonfigurationen führt.

Lösung

Verwenden Sie Parameterobjekte oder Data Transfer Objects (DTOs), um verwandte Parameter zu gruppieren. Wenden Sie das Builder-Pattern für komplexe Objektkonstruktion an. Verwenden Sie benannte Parameter, wenn die Sprache dies unterstützt. Zerlegen Sie komplexe Funktionen in kleinere, fokussierte Funktionen. Wenden Sie das Single-Responsibility-Prinzip an - wenn eine Funktion viele Parameter benötigt, tut sie wahrscheinlich zu viel. Verwenden Sie Standardparameterwerte für optionale Einstellungen. Erstellen Sie überladene Methoden für häufige Anwendungsfälle. Dokumentieren Sie Parameter klar und verwenden Sie aussagekräftige Parameternamen.

Häufige Auswirkungen

AuswirkungDetails
AndereBereich: Ändere

Reduzierte Wartbarkeit - Funktionen mit vielen Parametern sind schwer zu verstehen, korrekt zu verwenden und zu modifizieren.
AndereBereich: Ändere

Qualitätsverschlechterung - Parameterverwechslung führt zu Fehlern, die Sicherheitsimplikationen haben können.
AndereBereich: Ändere

Reduzierte Zuverlässigkeit - Komplexe Funktionssignaturen erhöhen die Wahrscheinlichkeit von Aufruferfehlern.

Beispielcode

Anfälliger Code

// Anfällig: Zu viele Parameter (12 Parameter!)
public class VulnerableUserService {

    public User createUser(
        String username,
        String password,
        String email,
        String firstName,
        String lastName,
        String phone,
        String address,
        String city,
        String state,
        String zipCode,
        String country,
        boolean isAdmin  // Leicht versehentlich auf true zu setzen!
    ) {
        // Parameterverwechslung ist wahrscheinlich
        User user = new User();
        user.setUsername(username);
        user.setPassword(password);  // Welches war nochmal das Passwort?
        // ... viele weitere Zuweisungen
        user.setAdmin(isAdmin);
        return user;
    }

    // Aufrufer werden verwirrt:
    // createUser("john", "[email protected]", "password123", ...)  // FALSCHE REIHENFOLGE!
}

// Anfällig: Boolesche Parameter mit unklarer Bedeutung
public void configureConnection(
    String host,
    int port,
    String username,
    String password,
    boolean param1,  // Was ist das?
    boolean param2,  // Und das?
    boolean param3,  // Keine Ahnung!
    int param4,
    String param5
) {
    // Aufrufer schreiben: configureConnection("host", 443, "user", "pass", true, false, true, 30, "TLS")
    // Was bedeuten diese Booleans?
}
# Anfällig: Übermäßige Positionsparameter
def vulnerable_send_email(
    sender,
    recipient,
    cc,
    bcc,
    subject,
    body,
    html_body,
    attachments,
    priority,
    read_receipt,
    delivery_receipt,
    encrypt,
    sign,
    custom_headers
):
    """
    Aufrufer muss sich Reihenfolge von 14 Parametern merken!
    Leicht 'encrypt' und 'sign' Positionen zu verwechseln.
    """
    # Implementierung...
    pass


# Aufrufender Code ist verwirrend und fehleranfällig:
vulnerable_send_email(
    "[email protected]",
    "[email protected]",
    None,
    None,
    "Subject",
    "Body text",
    "<p>HTML body</p>",
    [],
    "high",
    True,   # read_receipt? oder delivery_receipt?
    False,  # encrypt? oder sign?
    True,   # Habe ich das richtig?
    False,
    {}
)
// Anfällig: Methode mit übermäßigen Parametern
public class VulnerablePaymentProcessor
{
    public PaymentResult ProcessPayment(
        string cardNumber,
        string cardHolderName,
        int expirationMonth,
        int expirationYear,
        string cvv,
        decimal amount,
        string currency,
        string merchantId,
        string orderId,
        string customerEmail,
        string billingAddress,
        string billingCity,
        string billingState,
        string billingZip,
        string billingCountry,
        bool saveCard,        // Position 16 - leicht zu verwechseln
        bool useThreeDS,      // Position 17
        string returnUrl,
        string cancelUrl,
        Dictionary<string, string> metadata
    )
    {
        // 20 Parameter! Sehr schwierig korrekt aufzurufen.
        // ...
        return new PaymentResult();
    }
}

// Aufrufer machen Fehler:
// processor.ProcessPayment(card, name, 12, 2025, "123", 99.99, "USD",
//     merchant, order, email, addr, city, state, zip, country,
//     true, false, ...  // Welcher Boolean ist welcher?!

Korrigierter Code

// Korrigiert: Verwendung von Parameterobjekten und Builder-Pattern
public class FixedUserService {

    // Korrigiert: Parameterobjekt gruppiert verwandte Daten
    public User createUser(UserCreationRequest request) {
        User user = new User();
        user.setUsername(request.getUsername());
        user.setPassword(request.getPassword());
        user.setEmail(request.getEmail());
        user.setProfile(request.getProfile());
        user.setAddress(request.getAddress());
        user.setAdmin(request.isAdmin());
        return user;
    }
}

// Korrigiert: Builder-Pattern für komplexe Objektkonstruktion
public class UserCreationRequest {
    private final String username;
    private final String password;
    private final String email;
    private final UserProfile profile;
    private final Address address;
    private final boolean isAdmin;

    private UserCreationRequest(Builder builder) {
        this.username = builder.username;
        this.password = builder.password;
        this.email = builder.email;
        this.profile = builder.profile;
        this.address = builder.address;
        this.isAdmin = builder.isAdmin;
    }

    // Getter...

    public static class Builder {
        // Erforderliche Parameter
        private final String username;
        private final String password;
        private final String email;

        // Optionale Parameter mit Standardwerten
        private UserProfile profile = new UserProfile();
        private Address address = null;
        private boolean isAdmin = false;  // Sicherer Standardwert!

        public Builder(String username, String password, String email) {
            this.username = username;
            this.password = password;
            this.email = email;
        }

        public Builder profile(UserProfile profile) {
            this.profile = profile;
            return this;
        }

        public Builder address(Address address) {
            this.address = address;
            return this;
        }

        public Builder admin(boolean isAdmin) {
            this.isAdmin = isAdmin;
            return this;
        }

        public UserCreationRequest build() {
            return new UserCreationRequest(this);
        }
    }
}

// Korrigiert: Klare, lesbare Aufrufstelle
UserCreationRequest request = new UserCreationRequest.Builder(
        "johndoe", "SecurePass123!", "[email protected]")
    .profile(new UserProfile("John", "Doe", "+1234567890"))
    .address(new Address("123 Main St", "Springfield", "IL", "62701", "US"))
    .admin(false)  // Explizit benannt - keine Verwechslung!
    .build();

User user = userService.createUser(request);
# Korrigiert: Verwendung von Dataclasses und Schlüsselwortargumenten
from dataclasses import dataclass, field
from typing import Optional, List, Dict


@dataclass
class EmailMessage:
    """Parameterobjekt für E-Mail-Konfiguration"""
    sender: str
    recipient: str
    subject: str
    body: str
    cc: Optional[List[str]] = None
    bcc: Optional[List[str]] = None
    html_body: Optional[str] = None
    attachments: List[str] = field(default_factory=list)


@dataclass
class EmailOptions:
    """Separates Objekt für E-Mail-Optionen"""
    priority: str = "normal"
    read_receipt: bool = False
    delivery_receipt: bool = False
    encrypt: bool = False
    sign: bool = False
    custom_headers: Dict[str, str] = field(default_factory=dict)


def fixed_send_email(message: EmailMessage, options: Optional[EmailOptions] = None):
    """
    Korrigiert: Zwei klare Parameterobjekte statt 14 Parameter.
    """
    options = options or EmailOptions()
    # Implementierung mit message und options
    pass


# Korrigiert: Klare, selbstdokumentierende Aufrufstelle
message = EmailMessage(
    sender="[email protected]",
    recipient="[email protected]",
    subject="Wichtiges Update",
    body="Bitte überprüfen Sie das angehängte Dokument.",
    cc=["[email protected]"]
)

options = EmailOptions(
    priority="high",
    encrypt=True,  # Klar benannt!
    sign=True      # Keine Verwechslung!
)

fixed_send_email(message, options)
// Korrigiert: Verwendung von Parameterobjekten und Records
public class FixedPaymentProcessor
{
    public PaymentResult ProcessPayment(PaymentRequest request)
    {
        // Einzelnes Parameterobjekt enthält alles Benötigte
        ValidateRequest(request);
        return ExecutePayment(request);
    }
}

// Korrigiert: Unveränderliche Record-Typen für Parametergruppen
public record CardDetails(
    string CardNumber,
    string CardHolderName,
    int ExpirationMonth,
    int ExpirationYear,
    string Cvv
);

public record BillingAddress(
    string Street,
    string City,
    string State,
    string ZipCode,
    string Country
);

public record PaymentOptions
{
    public bool SaveCard { get; init; } = false;
    public bool UseThreeDS { get; init; } = true;  // Sicherer Standardwert
    public string? ReturnUrl { get; init; }
    public string? CancelUrl { get; init; }
    public Dictionary<string, string>? Metadata { get; init; }
}

public record PaymentRequest(
    CardDetails Card,
    decimal Amount,
    string Currency,
    string MerchantId,
    string OrderId,
    string CustomerEmail,
    BillingAddress BillingAddress,
    PaymentOptions? Options = null
);

// Korrigiert: Klare, lesbare Verwendung
var request = new PaymentRequest(
    Card: new CardDetails("4111111111111111", "John Doe", 12, 2025, "123"),
    Amount: 99.99m,
    Currency: "USD",
    MerchantId: "merchant_123",
    OrderId: "order_456",
    CustomerEmail: "[email protected]",
    BillingAddress: new BillingAddress("123 Main St", "Springfield", "IL", "62701", "US"),
    Options: new PaymentOptions
    {
        SaveCard = true,
        UseThreeDS = true  // Benannter Parameter - keine Verwechslung
    }
);

var result = processor.ProcessPayment(request);

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-1120: Excessive Code Complexity (verwandt)
  • CWE-1226: Complexity Issues (Kategoriemitglied)

Referenzen

  1. MITRE Corporation. "CWE-1064: Invokable Control Element with Signature Containing an Excessive Number of Parameters." https://cwe.mitre.org/data/definitions/1064.html

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

  3. Fowler, Martin. "Refactoring: Improving the Design of Existing Code."