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
| Auswirkung | Details |
|---|---|
| Sonstige | Bereich: Sonstige Qualitätsverschlechterung - Anwendungen können sich unvorhersehbar verhalten, wenn Spezifikationen nicht befolgt werden, was zu Zuverlässigkeitsproblemen führt. |
| Integrität | Bereich: Integrität Variiert nach Kontext - Sicherheitsprotokolle können ihre Garantien nicht bieten, wenn Implementierungsanforderungen verletzt werden. |
| Vertraulichkeit | Bereich: 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
- MITRE Corporation. "CWE-573: Improper Following of Specification by Caller." https://cwe.mitre.org/data/definitions/573.html
- POSIX.1-2017 Spezifikation für Signal-Behandlung und Async-Signal-Sicherheit.
- Oracle. "JDBC API Specification."