Akzeptanz von zusätzlichen nicht vertrauenswürdigen Daten mit vertrauenswürdigen Daten
Beschreibung
Akzeptanz von zusätzlichen nicht vertrauenswürdigen Daten mit vertrauenswürdigen Daten ist eine Schwachstelle, die auftritt, wenn ein Produkt bei der Verarbeitung vertrauenswürdiger Daten auch alle nicht vertrauenswürdigen Daten akzeptiert, die mit den vertrauenswürdigen Daten enthalten sind, und die nicht vertrauenswürdigen Daten behandelt, als wären sie vertrauenswürdig. Diese Schwäche stellt ein fundamentales Versagen dar, zwischen authentifizierten und nicht authentifizierten Informationen innerhalb eines Datenpakets zu unterscheiden. Häufige Manifestationen umfassen das Akzeptieren zusätzlicher Felder in signierten Nachrichten, die nicht Teil des ursprünglich signierten Inhalts waren, das Vertrauen auf alle Einträge in einer DNS-Antwort, wenn nur bestimmte Einträge authentifiziert wurden, das Akzeptieren zusätzlicher Parameter in authentifizierten API-Antworten und das Einschließen nicht vertrauenswürdiger Metadaten neben vertrauenswürdigen Inhalten. Die Schwachstelle nutzt die Annahme aus, dass wenn einige Daten vertrauenswürdig sind, alle begleitenden Daten ebenfalls vertrauenswürdig sein müssen.
Risiko
Das Akzeptieren nicht vertrauenswürdiger Daten, die mit vertrauenswürdigen Daten gebündelt sind, ermöglicht Angreifern, bösartige Inhalte zu injizieren, die das Vertrauen legitimer Daten erben. Bei der Zertifikatsvalidierung können Angreifer Zertifikate fälschen, indem sie zusätzliche Daten in Signaturen einschließen, die Zertifikatsketten-Manipulation ermöglichen. DNS-Antworten können zusätzliche Einträge über das Abgefragte hinaus enthalten, was Cache-Poisoning-Angriffe ermöglicht, bei denen Angreifer Einträge für Domains injizieren, die sie nicht kontrollieren. API-Antworten, die teilweise signiert sind, ermöglichen Angreifern, unsignierte Felder hinzuzufügen, die die Anwendung als vertrauenswürdig verarbeitet. Firmware-Updates mit partieller Signaturabdeckung ermöglichen bösartige Code-Injektion in unsignierten Abschnitten. Das Risiko wird verstärkt, da Anwendungen oft Vertrauensentscheidungen auf Container-Ebene treffen (z.B. "diese Nachricht ist signiert") anstatt auf individueller Datenelementebene, was eine Vertrauenseskalations-Schwachstelle erzeugt, bei der alle Daten im Container vertraut werden, unabhängig davon, was tatsächlich authentifiziert wurde.
Lösung
Implementieren Sie strikte Datenvalidierung, die zwischen authentifizierten und nicht authentifizierten Teilen von Daten unterscheidet. Für signierte Daten verarbeiten Sie nur Felder, die explizit von der Signatur abgedeckt werden, und lehnen Sie alle zusätzlichen Felder ab oder ignorieren Sie sie. Bei DNS-Antworten cachen Sie nur Einträge, die direkt die Abfrage beantworten, und validieren Sie, dass Authority- und Additional-Abschnitte für die abgefragte Domain relevant sind. Für API-Antworten definieren Sie explizite Schemas und lehnen Sie Antworten mit unerwarteten Feldern ab. Implementieren Sie "Sign-then-Encrypt" anstelle von "Encrypt-then-Sign", um Manipulation der Grenzen signierter Inhalte zu verhindern. Verwenden Sie kryptografische Techniken wie kanonische Serialisierung, die sicherstellen, dass Signaturen genau die beabsichtigten Daten abdecken. Wenden Sie das Prinzip der minimalen Autorität an - vertrauen Sie nur den minimal notwendigen Daten und behandeln Sie alle zusätzlichen Daten als nicht vertrauenswürdig.
Häufige Auswirkungen
| Auswirkung | Details |
|---|---|
| Zugriffskontrolle | Umfang: Zugriffskontrolle Angreifer können Zugriffskontrollen umgehen, indem sie unbefugte Daten mit autorisierten Daten bündeln und Zugang zu Ressourcen oder Funktionen erhalten, auf die sie keinen Zugriff haben sollten. |
| Integrität | Umfang: Integrität Das Akzeptieren zusätzlicher nicht vertrauenswürdiger Daten ermöglicht Angreifern, Anwendungsverhalten zu modifizieren, bösartige Inhalte zu injizieren oder Datenspeicher mit nicht authentifizierten Informationen zu korrumpieren. |
| Authentifizierung | Umfang: Authentifizierung Vertrauensgrenzen-Verletzungen ermöglichen Angreifern, Zertifikate oder Anmeldedaten zu fälschen, indem sie Signaturabdeckung manipulieren, um bösartige Daten einzuschließen. |
Beispielcode
Anfälliger Code (Python/Java)
Die folgenden Beispiele demonstrieren das Akzeptieren nicht vertrauenswürdiger Daten mit vertrauenswürdigen Daten:
# Anfällig: Akzeptieren von zusätzlichen nicht vertrauenswürdigen Daten
import json
import hmac
import hashlib
from typing import Dict, Any
# Anfällig: Alle Felder aus signierter Nachricht verarbeiten
def vulnerable_process_signed_message(message_json: str, signature: str,
secret_key: bytes) -> Dict[str, Any]:
message = json.loads(message_json)
# Anfällig: Nur Signatur deckt "signed_data" Feld ab
signed_portion = message.get('signed_data', {})
expected_sig = hmac.new(
secret_key,
json.dumps(signed_portion, sort_keys=True).encode(),
hashlib.sha256
).hexdigest()
if not hmac.compare_digest(signature, expected_sig):
raise ValueError("Ungültige Signatur")
# Anfällig: Verarbeitet ALLE Felder, nicht nur signierte
# Angreifer kann "admin": true zur Nachricht hinzufügen
return message # Enthält unsignierte Felder!
# Anfällig: DNS-Antwort mit zusätzlichen Einträgen
class VulnerableDNSCache:
def __init__(self):
self.cache = {}
def process_response(self, query_domain: str, response: Dict):
# Anfällig: Alle Einträge aus Antwort cachen
# auch wenn sie nicht Teil der Abfrage waren
# Answer-Sektion - was wir abgefragt haben
for record in response.get('answers', []):
self.cache[record['name']] = record['address']
# Anfällig: Auch Authority-Sektion cachen
for record in response.get('authority', []):
self.cache[record['name']] = record['ns']
# Anfällig: Additional-Sektion cachen (kann injiziert werden)
for record in response.get('additional', []):
# Angreifer kann hier Einträge für beliebige Domains injizieren
self.cache[record['name']] = record['address']
# Anfällig: API-Antwort mit zusätzlichen Feldern
def vulnerable_process_api_response(response: Dict, signature: str,
public_key) -> Dict:
# Antwortstruktur:
# {
# "user_id": "123",
# "timestamp": "2024-01-01T00:00:00Z",
# "signature_covers": ["user_id", "timestamp"]
# }
# Anfällig: Nur bestimmte Felder verifizieren
signed_data = {k: response[k] for k in response.get('signature_covers', [])}
if not verify_signature(signed_data, signature, public_key):
raise ValueError("Ungültige Signatur")
# Anfällig: Gesamte Antwort einschließlich unsignierter Felder zurückgeben
# Angreifer fügt hinzu: "is_admin": true, "permissions": ["all"]
return response
# Anfällig: Zertifikat mit zusätzlichen Extensions
def vulnerable_validate_certificate(cert):
# Anfällig: Nur Kernfelder prüfen, nicht alle Extensions
if not verify_ca_signature(cert):
raise ValueError("Ungültige CA-Signatur")
if cert.not_before > now() or cert.not_after < now():
raise ValueError("Zertifikat abgelaufen")
# Anfällig: Alle Extensions verarbeiten, einschließlich nicht authentifizierter
# X.509 Extensions könnten angreifer-injizierte Daten enthalten
for extension in cert.extensions:
apply_extension(extension) # Enthält nicht vertrauenswürdige Extensions
return True
# Anfällig: Firmware-Update mit partieller Abdeckung
def vulnerable_apply_firmware(firmware_package: bytes, signature: bytes,
public_key):
# Paketformat: [header: 256 bytes][signed_code][extra_data]
header = firmware_package[:256]
code_length = int.from_bytes(header[0:4], 'big')
signed_code = firmware_package[256:256+code_length]
extra_data = firmware_package[256+code_length:] # Unsigniert!
# Anfällig: Nur signed_code wird verifiziert
if not verify_signature(signed_code, signature, public_key):
raise ValueError("Ungültige Signatur")
# Anfällig: Sowohl signierte als auch unsignierte Daten anwenden
apply_code(signed_code)
apply_config(extra_data) # Anfällig: Diese Daten sind NICHT signiert!
// Anfällig: Akzeptieren von zusätzlichen nicht vertrauenswürdigen Daten in Java
import java.util.*;
import javax.crypto.*;
public class VulnerableExtraneousData {
// Anfällig: Alle JSON-Felder aus signierter Nachricht verarbeiten
public Map<String, Object> vulnerableProcessMessage(
String messageJson, String signature, SecretKey key)
throws Exception {
Map<String, Object> message = parseJson(messageJson);
Map<String, Object> signedData =
(Map<String, Object>) message.get("signed_data");
// Anfällig: Nur signed_data ist authentifiziert
String expectedSig = computeHmac(signedData, key);
if (!MessageDigest.isEqual(
signature.getBytes(), expectedSig.getBytes())) {
throw new SecurityException("Ungültige Signatur");
}
// Anfällig: Gesamte Nachricht einschließlich unsignierter Felder zurückgeben
return message; // Enthält angreifer-injizierte Felder
}
// Anfällig: XML-Signatur mit zusätzlichen Elementen
public Document vulnerableProcessSignedXml(Document doc) throws Exception {
// XML-Struktur:
// <message>
// <SignedInfo>...</SignedInfo> <!-- Signiert -->
// <data>...</data> <!-- Signiert (referenziert) -->
// <extra>...</extra> <!-- NICHT signiert! -->
// </message>
XMLSignature signature = new XMLSignature(doc);
// Anfällig: Validiert nur SignedInfo-Referenzen
if (!signature.validate()) {
throw new SecurityException("Ungültige XML-Signatur");
}
// Anfällig: Gesamtes Dokument einschließlich unsignierter Elemente verarbeiten
return doc; // Enthält unsigniertes <extra> Element
}
// Anfällig: Token mit zusätzlichen Claims
public Map<String, Object> vulnerableProcessToken(String token, Key key) {
// Token: header.payload.signature
String[] parts = token.split("\\.");
Map<String, Object> header = decodeBase64Json(parts[0]);
Map<String, Object> payload = decodeBase64Json(parts[1]);
// Anfällig: Signatur deckt nur ursprüngliche Payload ab
// Aber Angreifer kann Base64 modifizieren um zusätzliche Claims einzuschließen
// durch JSON-Parsing-Eigenheiten oder Whitespace-Injektion
String signedPortion = parts[0] + "." + parts[1];
if (!verifySignature(signedPortion, parts[2], key)) {
throw new SecurityException("Ungültige Signatur");
}
// Anfällig: Parser könnte zusätzliche Daten einschließen
return payload;
}
// Anfällig: Konfigurationsdatei mit signierten und unsignierten Abschnitten
public void vulnerableLoadConfig(byte[] configData, byte[] signature,
PublicKey publicKey) throws Exception {
// Konfigurationsformat: [signed_section_length:4][signed][unsigned]
int signedLength = ByteBuffer.wrap(configData, 0, 4).getInt();
byte[] signedSection = Arrays.copyOfRange(configData, 4, 4 + signedLength);
byte[] unsignedSection = Arrays.copyOfRange(
configData, 4 + signedLength, configData.length);
// Anfällig: Nur signierten Abschnitt verifizieren
Signature sig = Signature.getInstance("SHA256withRSA");
sig.initVerify(publicKey);
sig.update(signedSection);
if (!sig.verify(signature)) {
throw new SecurityException("Ungültige Konfigurationssignatur");
}
// Anfällig: Beide Abschnitte anwenden
applySignedConfig(signedSection);
applyUnsignedConfig(unsignedSection); // Angreifer-kontrolliert!
}
// Anfällig: HTTP-Antwort mit zusätzlichen Headern
public void vulnerableProcessResponse(HttpResponse response,
String expectedBodyHash) {
// Anfällig: Nur Body wird auf Integrität geprüft
String actualHash = sha256(response.getBody());
if (!actualHash.equals(expectedBodyHash)) {
throw new SecurityException("Body-Integritätsprüfung fehlgeschlagen");
}
// Anfällig: Header verarbeiten die nicht auf Integrität geprüft wurden
String redirectUrl = response.getHeader("X-Redirect-To");
if (redirectUrl != null) {
redirect(redirectUrl); // Angreifer-injizierter Header
}
}
}
Korrigierter Code (Python/Java)
# Korrigiert: Nur authentifizierte Daten verarbeiten
import json
import hmac
import hashlib
from typing import Dict, Any, Set
# Korrigiert: Nur signierte Felder zurückgeben
def secure_process_signed_message(message_json: str, signature: str,
secret_key: bytes) -> Dict[str, Any]:
message = json.loads(message_json)
# Korrigiert: Nur den signierten Teil extrahieren
signed_portion = message.get('signed_data', {})
expected_sig = hmac.new(
secret_key,
json.dumps(signed_portion, sort_keys=True).encode(),
hashlib.sha256
).hexdigest()
if not hmac.compare_digest(signature, expected_sig):
raise ValueError("Ungültige Signatur")
# Korrigiert: Nur die signierten Daten zurückgeben
return signed_portion # Nur authentifizierte Daten
# Korrigiert: DNS-Cache mit strikter Antwortvalidierung
class SecureDNSCache:
def __init__(self):
self.cache = {}
def process_response(self, query_domain: str, response: Dict):
# Korrigiert: Nur Einträge cachen, die die Abfrage beantworten
for record in response.get('answers', []):
# Korrigiert: Verifizieren dass Eintrag für abgefragte Domain ist
if self._is_valid_answer(query_domain, record):
self.cache[record['name']] = record['address']
# Korrigiert: Authority-Sektion nur für Zone der abgefragten Domain
for record in response.get('authority', []):
if self._is_in_bailiwick(query_domain, record):
self.cache[record['name']] = record['ns']
# Korrigiert: Additional-Sektion nur für bereits vertrauenswürdige Namen
allowed_names = {query_domain} | self._get_ns_names(response)
for record in response.get('additional', []):
# Korrigiert: Nur cachen wenn von vertrauenswürdigen Einträgen referenziert
if record['name'] in allowed_names:
self.cache[record['name']] = record['address']
def _is_valid_answer(self, query_domain: str, record: Dict) -> bool:
# Eintrag muss für abgefragte Domain oder gültige CNAME-Kette sein
return record['name'] == query_domain or \
record['name'].endswith('.' + query_domain)
def _is_in_bailiwick(self, query_domain: str, record: Dict) -> bool:
# Authority muss für übergeordnete Zone der abgefragten Domain sein
parts = query_domain.split('.')
for i in range(len(parts)):
zone = '.'.join(parts[i:])
if record['name'] == zone:
return True
return False
def _get_ns_names(self, response: Dict) -> Set[str]:
return {r['ns'] for r in response.get('authority', [])}
# Korrigiert: API-Antwort mit striktem Schema
def secure_process_api_response(response: Dict, signature: str,
public_key, expected_schema: Set[str]) -> Dict:
# Korrigiert: Exakt erwartete Felder definieren
SIGNED_FIELDS = {'user_id', 'timestamp', 'action'}
# Korrigiert: Nur erwartete signierte Felder extrahieren
signed_data = {}
for field in SIGNED_FIELDS:
if field not in response:
raise ValueError(f"Erforderliches Feld fehlt: {field}")
signed_data[field] = response[field]
if not verify_signature(signed_data, signature, public_key):
raise ValueError("Ungültige Signatur")
# Korrigiert: Nur signierte, validierte Felder zurückgeben
return signed_data
# Korrigiert: Zertifikat mit validierten Extensions
def secure_validate_certificate(cert):
if not verify_ca_signature(cert):
raise ValueError("Ungültige CA-Signatur")
if cert.not_before > now() or cert.not_after < now():
raise ValueError("Zertifikat abgelaufen")
# Korrigiert: Nur bekannte, kritische Extensions verarbeiten
KNOWN_EXTENSIONS = {
'basic_constraints',
'key_usage',
'subject_alt_name'
}
for extension in cert.extensions:
if extension.oid in KNOWN_EXTENSIONS:
# Korrigiert: Nur bekannte Extensions verarbeitet
apply_extension(extension)
elif extension.critical:
# Korrigiert: Unbekannte kritische Extensions ablehnen
raise ValueError(f"Unbekannte kritische Extension: {extension.oid}")
# Korrigiert: Unbekannte nicht-kritische Extensions werden ignoriert
return True
# Korrigiert: Firmware-Update mit vollständiger Abdeckung
def secure_apply_firmware(firmware_package: bytes, signature: bytes,
public_key):
# Korrigiert: Signatur deckt GESAMTES Paket ab
if not verify_signature(firmware_package, signature, public_key):
raise ValueError("Ungültige Signatur")
# Korrigiert: Nach Verifizierung parsen
header = firmware_package[:256]
code_length = int.from_bytes(header[0:4], 'big')
code = firmware_package[256:256+code_length]
config = firmware_package[256+code_length:]
# Korrigiert: Alle Daten wurden verifiziert
apply_code(code)
apply_config(config) # Sicher: war Teil des signierten Pakets
// Korrigiert: Nur authentifizierte Daten in Java verarbeiten
import java.util.*;
import javax.crypto.*;
public class SecureExtraneousData {
// Korrigiert: Nur signierte Felder zurückgeben
public Map<String, Object> secureProcessMessage(
String messageJson, String signature, SecretKey key)
throws Exception {
Map<String, Object> message = parseJson(messageJson);
Map<String, Object> signedData =
(Map<String, Object>) message.get("signed_data");
if (signedData == null) {
throw new SecurityException("signed_data fehlt");
}
String expectedSig = computeHmac(signedData, key);
if (!MessageDigest.isEqual(
signature.getBytes(), expectedSig.getBytes())) {
throw new SecurityException("Ungültige Signatur");
}
// Korrigiert: Nur den signierten Teil zurückgeben
return new HashMap<>(signedData); // Nur authentifizierte Daten
}
// Korrigiert: XML-Signatur mit strikter Element-Validierung
public Map<String, Object> secureProcessSignedXml(Document doc)
throws Exception {
XMLSignature signature = new XMLSignature(doc);
if (!signature.validate()) {
throw new SecurityException("Ungültige XML-Signatur");
}
// Korrigiert: Nur signierte Referenzen extrahieren
Set<String> signedElements = signature.getSignedElementIds();
Map<String, Object> result = new HashMap<>();
for (String elementId : signedElements) {
Element element = doc.getElementById(elementId);
if (element != null) {
result.put(element.getTagName(), extractContent(element));
}
}
// Korrigiert: Nur von Signatur abgedeckte Elemente zurückgeben
return result;
}
// Korrigiert: Token mit exakter Payload-Validierung
public Map<String, Object> secureProcessToken(String token, Key key) {
String[] parts = token.split("\\.");
if (parts.length != 3) {
throw new SecurityException("Ungültiges Token-Format");
}
// Korrigiert: Signatur über exakte Eingabe verifizieren
String signedPortion = parts[0] + "." + parts[1];
if (!verifySignature(signedPortion, parts[2], key)) {
throw new SecurityException("Ungültige Signatur");
}
// Korrigiert: Mit striktem JSON-Parser parsen
Map<String, Object> payload = strictJsonParse(
new String(Base64.getUrlDecoder().decode(parts[1]))
);
// Korrigiert: Nur erwartete Claims erlauben
Set<String> allowedClaims = Set.of(
"sub", "iat", "exp", "iss", "aud"
);
Map<String, Object> filtered = new HashMap<>();
for (String claim : allowedClaims) {
if (payload.containsKey(claim)) {
filtered.put(claim, payload.get(claim));
}
}
// Korrigiert: Nur erlaubte, verifizierte Claims zurückgeben
return filtered;
}
// Korrigiert: Konfigurationsdatei mit Signatur über alles
public void secureLoadConfig(byte[] configData, byte[] signature,
PublicKey publicKey) throws Exception {
// Korrigiert: Signatur über GESAMTE Konfiguration verifizieren
Signature sig = Signature.getInstance("SHA256withRSA");
sig.initVerify(publicKey);
sig.update(configData);
if (!sig.verify(signature)) {
throw new SecurityException("Ungültige Konfigurationssignatur");
}
// Korrigiert: Nur nach vollständiger Verifizierung parsen
Config config = parseConfig(configData);
applyConfig(config); // Sicher: alle Daten waren signiert
}
// Korrigiert: HTTP-Antwort mit authentifizierten Headern
public void secureProcessResponse(HttpResponse response,
String expectedHash,
Set<String> signedHeaders) {
// Korrigiert: Hash deckt Body UND kritische Header ab
StringBuilder toHash = new StringBuilder();
for (String header : signedHeaders) {
toHash.append(header).append(":")
.append(response.getHeader(header)).append("\n");
}
toHash.append(response.getBody());
String actualHash = sha256(toHash.toString());
if (!actualHash.equals(expectedHash)) {
throw new SecurityException("Antwort-Integritätsprüfung fehlgeschlagen");
}
// Korrigiert: Nur Header verarbeiten die auf Integrität geprüft wurden
for (String header : signedHeaders) {
processHeader(header, response.getHeader(header));
}
}
private Map<String, Object> strictJsonParse(String json) {
// Strikten JSON-Parser verwenden der keine Duplikate
// oder nachfolgende Daten erlaubt
return new StrictJsonParser().parse(json);
}
}
Die Korrektur stellt sicher, dass nur explizit authentifizierte Daten verarbeitet werden und alle zusätzlichen Daten abgelehnt oder ignoriert werden.
Ausgenutzt in der Praxis
DNS-Cache-Poisoning (CVE-2002-0018)
DNS-Resolver akzeptierten zusätzliche Einträge in Antworten über das Abgefragte hinaus, was Angreifern ermöglichte, Einträge für beliebige Domains zu injizieren.
Zertifikats-Signatur-Fälschung (CVE-2006-5462)
Zusätzliche Daten in Zertifikatssignaturen ermöglichten das Fälschen von Zertifikatsketten durch Manipulation von Daten außerhalb des signierten Teils.
Tools zum Testen/Ausnutzen
-
Burp Suite — Zusätzliche Felder in API-Antworten und signierte Nachrichten injizieren.
-
DNS-Testwerkzeuge — DNS-Resolver-Verhalten mit zusätzlichen Einträgen testen.
-
jwt_tool — JWT-Handling mit zusätzlichen Claims testen.
CVE-Beispiele
-
CVE-2002-0018 — DNS akzeptiert Einträge ohne Autorität.
-
CVE-2006-5462 — Zertifikatssignatur mit zusätzlichen Daten.
Referenzen
-
MITRE Corporation. "CWE-349: Acceptance of Extraneous Untrusted Data With Trusted Data." Common Weakness Enumeration. https://cwe.mitre.org/data/definitions/349.html
-
OWASP Foundation. "Injection Flaws." https://owasp.org/www-community/Injection_Flaws
-
RFC 5155. "DNS Security (DNSSEC) Hashed Authenticated Denial of Existence." https://tools.ietf.org/html/rfc5155