Unsachgemäßes Befolgen der Spezifikation durch den Aufrufer

Beschreibung

Unsachgemäßes Befolgen der Spezifikation durch den Aufrufer ist eine Schwachstelle, bei der ein Produkt die durch die Implementierungssprache, Umgebung, Framework, Protokoll oder Plattform vorgeschriebenen Spezifikationen nicht einhält oder falsch befolgt. Bei der Nutzung externer Funktionalität wie APIs, Bibliotheken oder Protokollen ist es kritisch, dass der Aufrufer dies in Übereinstimmung mit den dokumentierten Anforderungen und Verträgen tut. Die Nichteinhaltung dieser Spezifikationen kann zu undefiniertem Verhalten, Sicherheitsschwachstellen, Datenkorruption oder Systemausfällen führen, die schwer vorherzusagen und zu diagnostizieren sein können.

Risiko

Die Verletzung von Spezifikationen erzeugt unvorhersehbares und oft gefährliches Verhalten. Sicherheitsprotokolle können stillschweigend versagen, wenn Implementierungsanforderungen nicht befolgt werden, wodurch Systeme trotz scheinbarer Sicherheit verwundbar bleiben. Kryptografische Implementierungen, die erforderliche Schritte wie ordnungsgemäße Padding-Verifizierung überspringen, können Signaturfälschungsangriffe ermöglichen. API-Missbrauch kann zu Speicherkorruption, Ressourcenlecks oder Privilegieneskalation führen. Das Risiko wird verstärkt, weil solche Verletzungen oft in Tests funktionieren, aber in der Produktion oder unter gegnerischen Bedingungen katastrophal versagen. Zusätzlich lösen Spezifikationsverletzungen möglicherweise keine offensichtlichen Fehler aus, was Schwachstellen schwer zu erkennen macht.

Lösung

Lesen und verstehen Sie die vollständige Spezifikation für jede externe Funktionalität gründlich vor der Verwendung. Befolgen Sie alle dokumentierten Anforderungen, einschließlich Fehlerbehandlung, Initialisierungssequenzen und Bereinigungsprozeduren. Achten Sie besonders auf sicherheitsrelevante Spezifikationen in kryptografischen Bibliotheken und Authentifizierungsprotokollen. Verwenden Sie statische Analysewerkzeuge, die Spezifikationsverletzungen erkennen können. Implementieren Sie umfassende Tests, die Randfälle und Fehlerbedingungen abdecken, die in der Dokumentation spezifiziert sind. Überprüfen Sie Code regelmäßig auf Einhaltung aktualisierter Spezifikationen. Erwägen Sie die Verwendung von Wrapper-Funktionen, die korrekte Verwendungsmuster erzwingen.

Häufige Auswirkungen

AuswirkungDetails
SonstigeBereich: Sonstige

Qualitätsverschlechterung - Anwendungen können sich unvorhersehbar verhalten, wenn Spezifikationen nicht befolgt werden, was zu Zuverlässigkeitsproblemen führt.
IntegritätBereich: Integrität

Variiert nach Kontext - Sicherheitsprotokolle können ihre Garantien nicht bieten, wenn Implementierungsanforderungen verletzt werden.
VertraulichkeitBereich: Vertraulichkeit

Variiert nach Kontext - Unsachgemäße Verwendung von kryptografischen oder Authentifizierungs-APIs kann sensible Daten oder Anmeldeinformationen offenlegen.

Beispielcode

Verwundbarer Code

// Verwundbar: JDBC-Spezifikation für Verbindungsbereinigung nicht befolgt
import java.sql.*;

public class VulnerableJdbcUsage {

    // Verwundbar: Spezifikation für Ressourcenbereinigung nicht befolgt
    public List<User> getUsers() throws SQLException {
        Connection conn = DriverManager.getConnection(DB_URL, USER, PASS);
        Statement stmt = conn.createStatement();
        ResultSet rs = stmt.executeQuery("SELECT * FROM users");

        List<User> users = new ArrayList<>();
        while (rs.next()) {
            users.add(new User(rs.getString("name"), rs.getInt("id")));
        }

        // Verwundbar: Ressourcen nicht in richtiger Reihenfolge geschlossen
        // Spezifikation erfordert Schließen in umgekehrter Erstellungsreihenfolge
        conn.close();  // Falsch! Sollte ResultSet, Statement, dann Connection schließen

        return users;
        // ResultSet und Statement können lecken
    }

    // Verwundbar: PreparedStatement-Spezifikation nicht befolgt
    public void updateUser(String userId, String name) throws SQLException {
        Connection conn = DriverManager.getConnection(DB_URL, USER, PASS);

        // Verwundbar: PreparedStatement falsch wiederverwendet
        PreparedStatement pstmt = conn.prepareStatement(
            "UPDATE users SET name = ? WHERE id = ?");

        // Spezifikation sagt Parameter müssen vor jeder Ausführung gesetzt werden
        pstmt.setString(1, name);
        pstmt.setString(2, userId);
        pstmt.executeUpdate();

        // Verwundbar: Wiederverwendung ohne Parameter zu löschen
        pstmt.setString(1, "neuer name");
        // Fehlt: pstmt.setString(2, newId);
        pstmt.executeUpdate();  // Zweiter Parameter von vorher beibehalten
    }
}
// Verwundbar: Kryptografische Spezifikation nicht befolgt
import javax.crypto.*;
import javax.crypto.spec.*;
import java.security.*;

public class VulnerableCryptoUsage {

    // Verwundbar: RSA ohne ordnungsgemäße Padding-Verifizierung
    public byte[] vulnerableDecrypt(byte[] ciphertext, PrivateKey key)
            throws Exception {

        Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
        cipher.init(Cipher.DECRYPT_MODE, key);

        // Verwundbar: Padding-Fehler nicht korrekt geprüft
        // Spezifikation erfordert Padding-Validierung um Oracle-Angriffe zu verhindern
        try {
            return cipher.doFinal(ciphertext);
        } catch (BadPaddingException e) {
            // Verwundbar: Rückgabe von null offenbart Padding-Fehler
            // Dies ermöglicht Bleichenbacher-artige Angriffe (CVE-2006-4339)
            return null;
        }
    }

    // Verwundbar: IV-Spezifikation für CBC-Modus nicht befolgt
    public byte[] vulnerableEncrypt(byte[] plaintext, SecretKey key)
            throws Exception {

        Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");

        // Verwundbar: Fester IV statt zufälligem verwendet
        // Spezifikation erfordert einzigartigen IV für jede Verschlüsselung
        byte[] fixedIv = new byte[16];  // Alles Nullen!
        IvParameterSpec ivSpec = new IvParameterSpec(fixedIv);

        cipher.init(Cipher.ENCRYPT_MODE, key, ivSpec);
        return cipher.doFinal(plaintext);
    }

    // Verwundbar: Schlüsselableitungsspezifikation nicht befolgt
    public SecretKey vulnerableKeyDerivation(String password) throws Exception {
        // Verwundbar: MD5 statt ordnungsgemäßem PBKDF verwendet
        // Spezifikation empfiehlt PBKDF2 mit Iterationszähler
        MessageDigest md = MessageDigest.getInstance("MD5");
        byte[] keyBytes = md.digest(password.getBytes());

        return new SecretKeySpec(keyBytes, "AES");
    }
}
// Verwundbar: POSIX-Signalspezifikation nicht befolgt
#include <signal.h>
#include <stdio.h>

// Verwundbar: Async-signal-unsichere Funktionen im Handler
void vulnerable_signal_handler(int sig) {
    // Verwundbar: printf ist nicht async-signal-sicher laut POSIX
    printf("Signal %d gefangen\n", sig);  // Verletzt Spezifikation

    // Verwundbar: malloc ist nicht async-signal-sicher
    char* buffer = malloc(100);  // Kann Deadlock verursachen

    // Verwundbar: exit ist nicht async-signal-sicher
    exit(1);  // Sollte _exit() im Signal-Handler verwenden
}

void setup_vulnerable_handler() {
    // Nicht-async-signal-sichere Funktionen in Handlern verwenden
    signal(SIGINT, vulnerable_signal_handler);
}

// Verwundbar: fork()-Spezifikation nicht befolgt
void vulnerable_fork_usage() {
    FILE* file = fopen("data.txt", "w");

    pid_t pid = fork();

    // Verwundbar: Eltern und Kind haben gleichen FILE*
    // Spezifikation sagt gepufferter I/O-Zustand wird dupliziert
    if (pid == 0) {
        fprintf(file, "Kind schreibt\n");
        fclose(file);
    } else {
        fprintf(file, "Eltern schreibt\n");
        fclose(file);
    }
    // Ausgabe kann beschädigt oder verschachtelt sein
}
# Verwundbar: Iterator-Spezifikation nicht befolgt
class VulnerableIterator:
    def __init__(self, items):
        self.items = items
        self.index = 0

    def __iter__(self):
        return self

    def __next__(self):
        if self.index < len(self.items):
            result = self.items[self.index]
            self.index += 1
            return result
        # Verwundbar: Spezifikation erfordert StopIteration auszulösen
        return None  # Falsch! Sollte StopIteration auslösen

# Verwundbar: Context-Manager-Spezifikation nicht befolgt
class VulnerableContextManager:
    def __init__(self):
        self.resource = None

    def __enter__(self):
        self.resource = acquire_resource()
        # Verwundbar: Muss etwas zurückgeben (normalerweise self)
        # Fehlende return-Anweisung

    def __exit__(self, exc_type, exc_val, exc_tb):
        # Verwundbar: Bereinigung bei Exception nicht behandelt
        if exc_type is None:
            release_resource(self.resource)
        # Spezifikation sagt Bereinigung sollte unabhängig von Exception erfolgen
        # Auch nicht True/False wie spezifiziert zurückgeben

Lösungscode

// Behoben: Ordnungsgemäße JDBC-Ressourcenverwaltung gemäß Spezifikation
import java.sql.*;

public class SecureJdbcUsage {

    // Behoben: try-with-resources gemäß Spezifikation verwenden
    public List<User> getUsers() throws SQLException {
        List<User> users = new ArrayList<>();

        // Behoben: Ressourcen werden automatisch in umgekehrter Reihenfolge geschlossen
        try (Connection conn = DriverManager.getConnection(DB_URL, USER, PASS);
             Statement stmt = conn.createStatement();
             ResultSet rs = stmt.executeQuery("SELECT * FROM users")) {

            while (rs.next()) {
                users.add(new User(rs.getString("name"), rs.getInt("id")));
            }
        }
        // Ressourcen ordnungsgemäß geschlossen: rs, stmt, conn (in umgekehrter Reihenfolge)

        return users;
    }

    // Behoben: Ordnungsgemäße PreparedStatement-Verwendung gemäß Spezifikation
    public void updateUsers(List<UserUpdate> updates) throws SQLException {
        try (Connection conn = DriverManager.getConnection(DB_URL, USER, PASS);
             PreparedStatement pstmt = conn.prepareStatement(
                 "UPDATE users SET name = ? WHERE id = ?")) {

            for (UserUpdate update : updates) {
                // Behoben: Alle Parameter vor jeder Ausführung löschen und setzen
                pstmt.clearParameters();
                pstmt.setString(1, update.getName());
                pstmt.setString(2, update.getId());
                pstmt.executeUpdate();
            }
        }
    }
}
// Behoben: Kryptografische Spezifikationen befolgen
import javax.crypto.*;
import javax.crypto.spec.*;
import java.security.*;

public class SecureCryptoUsage {

    // Behoben: Konstantzeit-Padding-Fehlerbehandlung
    public byte[] secureDecrypt(byte[] ciphertext, PrivateKey key)
            throws GeneralSecurityException {

        Cipher cipher = Cipher.getInstance("RSA/ECB/OAEPWithSHA-256AndMGF1Padding");
        cipher.init(Cipher.DECRYPT_MODE, key);

        // Behoben: Keine Timing-Informationen über Padding preisgeben
        // OAEP-Padding verwenden, das sicherer ist als PKCS#1 v1.5
        return cipher.doFinal(ciphertext);
        // Exception-Behandlung sollte unabhängig vom Fehlertyp einheitlich sein
    }

    // Behoben: Zufälliger IV gemäß Spezifikation für CBC-Modus
    public EncryptedData secureEncrypt(byte[] plaintext, SecretKey key)
            throws GeneralSecurityException {

        Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");

        // Behoben: Zufälligen IV gemäß Spezifikation generieren
        SecureRandom random = SecureRandom.getInstanceStrong();
        byte[] iv = new byte[12];  // GCM empfohlene IV-Größe
        random.nextBytes(iv);

        GCMParameterSpec gcmSpec = new GCMParameterSpec(128, iv);
        cipher.init(Cipher.ENCRYPT_MODE, key, gcmSpec);

        byte[] ciphertext = cipher.doFinal(plaintext);

        // IV mit Ciphertext zurückgeben wie Spezifikation erfordert
        return new EncryptedData(iv, ciphertext);
    }

    // Behoben: Ordnungsgemäße Schlüsselableitung gemäß PKCS#5-Spezifikation
    public SecretKey secureKeyDerivation(String password, byte[] salt)
            throws GeneralSecurityException {

        // Behoben: PBKDF2 mit ordnungsgemäßem Iterationszähler gemäß Spezifikation
        SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA256");
        KeySpec spec = new PBEKeySpec(
            password.toCharArray(),
            salt,
            310000,  // OWASP empfohlene Mindestiterationen
            256      // Schlüssellänge in Bits
        );

        byte[] keyBytes = factory.generateSecret(spec).getEncoded();
        return new SecretKeySpec(keyBytes, "AES");
    }
}
// Behoben: POSIX-Signalspezifikation befolgen
#include <signal.h>
#include <unistd.h>
#include <string.h>

// Flag für Signal-Behandlung (sig_atomic_t ist async-signal-sicher)
static volatile sig_atomic_t signal_received = 0;

// Behoben: Nur async-signal-sichere Funktionen im Handler verwenden
void secure_signal_handler(int sig) {
    // Behoben: Nur Flag setzen, keine unsicheren Funktionen aufrufen
    signal_received = sig;

    // Behoben: Wenn schreiben nötig, async-signal-sicheres write() verwenden
    const char msg[] = "Signal empfangen\n";
    write(STDERR_FILENO, msg, sizeof(msg) - 1);
}

void setup_secure_handler() {
    struct sigaction sa;
    memset(&sa, 0, sizeof(sa));
    sa.sa_handler = secure_signal_handler;
    sigemptyset(&sa.sa_mask);
    sa.sa_flags = SA_RESTART;  // Unterbrochene Syscalls neustarten

    sigaction(SIGINT, &sa, NULL);
}

void main_loop() {
    while (!signal_received) {
        // Arbeit erledigen
        // Flag periodisch prüfen und Signal hier sicher behandeln
    }
    // Signal im Hauptkontext behandeln wo alle Funktionen sicher sind
    printf("Signal %d behandelt\n", signal_received);
}

// Behoben: fork()-Spezifikation für Datei-I/O befolgen
void secure_fork_usage() {
    pid_t pid = fork();

    if (pid == 0) {
        // Kind: Eigenes Datei-Handle öffnen
        FILE* file = fopen("kind_daten.txt", "w");
        if (file) {
            fprintf(file, "Kind schreibt\n");
            fclose(file);
        }
        _exit(0);  // _exit() im Kind nach fork verwenden
    } else if (pid > 0) {
        // Eltern: Separate Datei verwenden
        FILE* file = fopen("eltern_daten.txt", "w");
        if (file) {
            fprintf(file, "Eltern schreibt\n");
            fclose(file);
        }
        wait(NULL);
    }
}
# Behoben: Iterator-Spezifikation befolgen
class SecureIterator:
    def __init__(self, items):
        self.items = items
        self.index = 0

    def __iter__(self):
        return self

    def __next__(self):
        if self.index < len(self.items):
            result = self.items[self.index]
            self.index += 1
            return result
        # Behoben: StopIteration gemäß Spezifikation auslösen
        raise StopIteration

# Behoben: Context-Manager-Spezifikation befolgen
class SecureContextManager:
    def __init__(self):
        self.resource = None

    def __enter__(self):
        self.resource = acquire_resource()
        return self  # Behoben: self gemäß Spezifikation zurückgeben

    def __exit__(self, exc_type, exc_val, exc_tb):
        # Behoben: Immer bereinigen unabhängig von Exception
        if self.resource is not None:
            try:
                release_resource(self.resource)
            except Exception:
                pass  # Sicherstellen dass Bereinigung während Exception-Behandlung nicht wirft
            finally:
                self.resource = None

        # Behoben: False zurückgeben um Exceptions zu propagieren (oder True um zu unterdrücken)
        return False

# Verwendung mit ordnungsgemäßer Spezifikationsbefolgung
with SecureContextManager() as ctx:
    ctx.do_work()
# Ressource garantiert freigegeben

CVE-Beispiele

  • CVE-2006-4339: OpenSSL RSA-Implementierung verifizierte PKCS#1-Padding nicht ordnungsgemäß, was Signaturfälschungsangriffe ermöglichte.
  • CVE-2006-7140: Crypto++ Bibliothek entfernte Padding während Signaturverifizierung falsch, was gefälschte Signaturen ermöglichte.

Referenzen

  1. MITRE Corporation. "CWE-573: Improper Following of Specification by Caller." https://cwe.mitre.org/data/definitions/573.html
  2. POSIX.1-2017 Spezifikation für Signal-Behandlung und Async-Signal-Sicherheit.
  3. Oracle. "JDBC API Specification."