Falsche Bereitstellung der spezifizierten Funktionalität

Beschreibung

Falsche Bereitstellung der spezifizierten Funktionalität ist eine Schwachstelle, bei der Code nicht gemäß seinen veröffentlichten Spezifikationen oder dokumentiertem Verhalten arbeitet, was potenziell zu falscher Verwendung durch Aufrufer führt, die auf diese Dokumentation vertrauen. Wenn eine Funktion oder API anders als dokumentiert verhält — falsche Fehlercodes zurückgibt, beworbene Validierung weglässt oder undokumentierte Nebeneffekte hat — können Aufrufer, die der Spezifikation vertrauen, den Code falsch verwenden, was zu Sicherheitslücken oder Zuverlässigkeitsproblemen führt.

Risiko

Wenn Code von Spezifikationen abweicht, werden die Sicherheitsannahmen der Aufrufer ungültig. Funktionen, die behaupten, Eingaben zu validieren, es aber nicht tun, können Injektionsangriffe ermöglichen. Fehlercodes, die tatsächliche Fehler nicht widerspiegeln, führen zu unsachgemäßer Fehlerbehandlung. Sicherheitsbibliotheken, die beworbene Prüfungen nicht durchführen, bieten falsches Vertrauen, während sie Systeme verwundbar lassen. API-Konsumenten bauen Systeme unter der Annahme dokumentierten Verhaltens, was systemische Schwachstellen schafft, wenn dieses Verhalten abweicht.

Lösung

Stellen Sie sicher, dass Code strikt seinen dokumentierten Spezifikationen entspricht. Wenn Spezifikationen nicht erfüllt werden können, aktualisieren Sie die Dokumentation, um das tatsächliche Verhalten widerzuspiegeln, und kommunizieren Sie Änderungen an Konsumenten. Implementieren Sie umfassende Tests, die verifizieren, dass Verhalten den Spezifikationen entspricht. Verwenden Sie vertragsbasierte Programmierung oder Assertions, um dokumentierte Vor-/Nachbedingungen durchzusetzen. Führen Sie Code-Reviews durch, die speziell die Spezifikationskonformität prüfen.

Häufige Auswirkungen

AuswirkungDetails
SonstigesBereich: Sonstige

Qualitätsverschlechterung - Anwendungen funktionieren nicht, wenn abhängiger Code sich nicht wie spezifiziert verhält.
ZugriffskontrolleBereich: Zugriffskontrolle

Schutzmechanismus umgehen - Sicherheitsprüfungen, die beworbene Validierung nicht durchführen, ermöglichen Umgehungen.
IntegritätBereich: Integrität

Unerwarteter Zustand - Systeme geraten in inkonsistente Zustände, wenn Funktionen dokumentierte Invarianten nicht einhalten.

Beispielcode und Lösung

Verwundbarer Code

// Verwundbar: Servlet behauptet zu validieren, tut es aber nicht
/**
 * Verarbeitet Benutzereingabe.
 * @param input Benutzereingabe - validiert für SQL-Injection
 * @return verarbeitetes Ergebnis
 */
@WebServlet("/process")
public class VerwundbaresServlet extends HttpServlet {

    @Override
    protected void doPost(HttpServletRequest request,
                         HttpServletResponse response)
            throws ServletException, IOException {

        String input = request.getParameter("data");

        try {
            // Dokumentation behauptet SQL-Injection-Validierung
            // aber KEINE VALIDIERUNG WIRD TATSÄCHLICH DURCHGEFÜHRT!
            String result = processData(input);  // Verwundbar!
            response.getWriter().write(result);
        } catch (Exception e) {
            // Verwundbar: Gibt 200 OK auch bei Fehler zurück!
            response.setStatus(200);  // Sollte Fehlerstatus sein
            response.getWriter().write("Verarbeitet");
        }
    }

    private String processData(String input) throws SQLException {
        // Verwendet unvalidierte Eingabe direkt in Query
        return db.query("SELECT * FROM data WHERE value = '" + input + "'");
    }
}
# Verwundbar: Passwortvalidierungsfunktion funktioniert nicht wie dokumentiert
def validiere_passwort(password):
    """
    Validiert, dass Passwort Sicherheitsanforderungen erfüllt.

    Anforderungen:
    - Mindestens 8 Zeichen
    - Mindestens ein Großbuchstabe
    - Mindestens ein Kleinbuchstabe
    - Mindestens eine Ziffer
    - Mindestens ein Sonderzeichen

    Rückgabe:
        True wenn Passwort gültig, sonst False
    """
    # VERWUNDBAR: Prüft nur Länge, nicht andere Anforderungen!
    if len(password) >= 8:
        return True  # Dokumentation sagt, es prüft alles!
    return False

# Aufrufer vertraut der Dokumentation
def registriere_benutzer(username, password):
    if not validiere_passwort(password):
        raise ValueError("Passwort erfüllt Anforderungen nicht")

    # Aufrufer nimmt an, Passwort hat Großbuchstabe, Ziffer, Sonderzeichen...
    # Aber es könnte einfach "aaaaaaaa" sein - erfüllt nur Längenanforderung
    erstelle_benutzer(username, password)
// Verwundbar: Cache hält TTL nicht ein wie dokumentiert
/**
 * Thread-sicherer Cache mit Time-to-Live-Unterstützung.
 * Elemente werden automatisch nach Ablauf der TTL entfernt.
 */
public class VerwundbarerCache<K, V> {
    private final Map<K, CacheEntry<V>> cache = new ConcurrentHashMap<>();

    /**
     * Holt Wert aus Cache.
     * @return Wert wenn vorhanden und nicht abgelaufen, sonst null
     */
    public V get(K key) {
        CacheEntry<V> entry = cache.get(key);
        if (entry == null) {
            return null;
        }

        // VERWUNDBAR: TTL-Prüfung ist dokumentiert aber nicht implementiert!
        // Abgelaufene Einträge werden trotzdem zurückgegeben
        // if (entry.isExpired()) {
        //     cache.remove(key);
        //     return null;
        // }

        return entry.getValue();  // Gibt abgelaufene Einträge zurück!
    }
}

Sichere Lösung

// Sicher: Servlet mit ordnungsgemäßer Validierung und Fehlerbehandlung
@WebServlet("/process")
public class SicheresServlet extends HttpServlet {

    @Override
    protected void doPost(HttpServletRequest request,
                         HttpServletResponse response)
            throws ServletException, IOException {

        String input = request.getParameter("data");

        try {
            // Sicher: Tatsächlich validieren wie dokumentiert
            validateInput(input);

            String result = processData(input);
            response.setStatus(HttpServletResponse.SC_OK);
            response.getWriter().write(result);

        } catch (ValidationException e) {
            // Sicher: Ordnungsgemäße Fehlerantwort
            response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
            response.getWriter().write("Ungültige Eingabe: " + e.getMessage());

        } catch (SQLException e) {
            // Sicher: Korrekter Fehlercode für Serverfehler
            response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
            response.getWriter().write("Verarbeitungsfehler");
            logger.error("Datenbankfehler", e);
        }
    }

    private void validateInput(String input) throws ValidationException {
        // Sicher: Dokumentierte Validierung implementieren
        if (input == null) {
            throw new ValidationException("Eingabe erforderlich");
        }
        // Auf SQL-Injection-Muster prüfen
        if (containsSqlInjection(input)) {
            throw new ValidationException("Ungültige Zeichen in Eingabe");
        }
    }

    private String processData(String input) throws SQLException {
        // Sicher: Prepared Statement verwenden
        PreparedStatement stmt = db.prepareStatement(
            "SELECT * FROM data WHERE value = ?");
        stmt.setString(1, input);
        return executeAndFormat(stmt);
    }
}
# Sicher: Passwortvalidierung entspricht Dokumentation
import re

def validiere_passwort(password: str) -> bool:
    """
    Validiert, dass Passwort Sicherheitsanforderungen erfüllt.

    Anforderungen:
    - Mindestens 8 Zeichen
    - Mindestens ein Großbuchstabe
    - Mindestens ein Kleinbuchstabe
    - Mindestens eine Ziffer
    - Mindestens ein Sonderzeichen

    Rückgabe:
        True wenn Passwort gültig, sonst False
    """
    if password is None:
        return False

    # Sicher: ALLE dokumentierten Anforderungen implementieren
    if len(password) < 8:
        return False

    if not re.search(r'[A-Z]', password):
        return False

    if not re.search(r'[a-z]', password):
        return False

    if not re.search(r'\d', password):
        return False

    if not re.search(r'[!@#$%^&*(),.?":{}|<>]', password):
        return False

    return True
// Sicher: Cache hält TTL ein wie dokumentiert
public class SichererCache<K, V> {

    public V get(K key) {
        CacheEntry<V> entry = cache.get(key);
        if (entry == null) {
            return null;
        }

        // Sicher: TTL-Prüfung wie dokumentiert implementieren
        if (entry.isExpired()) {
            cache.remove(key);  // Abgelaufenen Eintrag entfernen
            return null;  // null für abgelaufene Einträge zurückgeben
        }

        return entry.getValue();
    }
}

Ausgenutzt in der Praxis

PKCS#11-Bibliothek Signaturprüfungsfehler (2002)

Eine PKCS#11-Bibliothek gab "OK" zurück, auch wenn Signaturen ungültig waren. Anwendungen, die der Dokumentation vertrauten, akzeptierten gefälschte Signaturen.

Microsoft Windows "Verlauf löschen" (1999)

Die "Verlauf löschen"-Funktion in Internet Explorer behauptete, alle besuchten URLs zu löschen, tat dies aber nicht vollständig, was zu Datenschutzproblemen führte.


Tools zum Testen und Ausnutzen


CVE-Beispiele

  • CVE-2002-1446 — PKCS#11-Bibliothek Fehlerprüfung gab "OK" trotz ungültiger Signaturen zurück.

  • CVE-2001-1559 — Systemaufruf gab falschen Wert zurück, führte zu NULL-Pointer-Dereferenzierung.

  • CVE-1999-1446 — "Verlauf löschen" UI-Funktion löschte besuchte URLs-Liste nicht wirklich.


Referenzen

  1. MITRE Corporation. "CWE-684: Incorrect Provision of Specified Functionality." https://cwe.mitre.org/data/definitions/684.html

  2. Meyer, Bertrand. "Design by Contract." https://www.eiffel.com/values/design-by-contract/

  3. OWASP. "API Security Guidelines." https://owasp.org/www-project-api-security/