Unsachgemäße Verifizierung der Quelle eines Kommunikationskanals
Beschreibung
Unsachgemäße Verifizierung der Quelle eines Kommunikationskanals tritt auf, wenn ein Produkt eingehende Kommunikationen oder Anfragen akzeptiert, ohne zu verifizieren, dass sie von einer erwarteten oder autorisierten Quelle stammen. Viele Sicherheitskontrollen verlassen sich darauf, der deklarierten Quelle einer Nachricht zu vertrauen, aber ohne ordnungsgemäße Verifizierung können Angreifer die Quelle fälschen, um unautorisierten Zugang zu erhalten, unbeabsichtigte Aktionen auszulösen oder Caches und Datenspeicher zu vergiften. Diese Schwachstelle ist besonders verbreitet in Netzwerkprotokollen, Inter-Prozess-Kommunikation und mobilen Anwendungs-Handlern.
Risiko
Das Versäumnis, Kommunikationsquellen zu verifizieren, ermöglicht verschiedene Angriffsvektoren. DNS-Cache-Poisoning ermöglicht es Angreifern, Datenverkehr auf bösartige Server umzuleiten. Mobile Anwendungen können privilegierte Operationen ausführen, die von bösartigen Apps oder Websites ausgelöst werden. Webanwendungen können Daten von nicht vertrauenswürdigen Ursprüngen akzeptieren. Interne Dienste können von externen Angreifern zugegriffen werden, die interne Adressen fälschen. Authentifizierung kann umgangen werden, wenn Quellenverifizierung ordnungsgemäße Authentifizierung ersetzt. Die Auswirkungen reichen von Datenmanipulation bis hin zur vollständigen Systemkompromittierung, abhängig davon, welche Funktionalität offengelegt wird.
Lösung
Implementieren Sie kryptographische Authentifizierung für Kommunikationsquellen, wo möglich. Verwenden Sie signierte Tokens, TLS-Client-Zertifikate oder HMAC-basierte Verifizierung. Für mobile Apps validieren Sie Intent-Quellen und verwenden Sie Berechtigungen auf Signaturebene. Vertrauen Sie niemals Quell-Identifikatoren, die leicht gefälscht werden können (IP-Adressen, Referrer-Header). Für DNS implementieren Sie DNSSEC und validieren Sie Antworten kryptographisch. Verwenden Sie explizite Vertrauensbeziehungen anstelle von implizitem quellenbasiertem Vertrauen. Validieren Sie die vollständige Vertrauenskette für weitergeleitete Anfragen. Implementieren Sie Rate-Limiting und Anomalieerkennung für Anfragen von nicht verifizierten Quellen.
Häufige Auswirkungen
| Auswirkung | Details |
|---|---|
| Zugriffskontrolle | Bereich: Zugriffskontrolle Privilegien erlangen oder Identität annehmen - Angreifer können vertrauenswürdige Quellen imitieren, um unautorisierten Zugang zu Funktionalität zu erhalten. |
| Integrität | Bereich: Integrität Anwendungsdaten modifizieren - Cache-Poisoning oder Dateninjektion von gefälschten Quellen kann den Anwendungsstatus beschädigen. |
| Zugriffskontrolle | Bereich: Zugriffskontrolle Schutzmechanismus umgehen - Quellenbasierte Zugriffskontrollen werden umgangen, wenn Quellen gefälscht werden können. |
Beispielcode
Anfälliger Code
// Anfällig: Android BroadcastReceiver ohne Quellenverifizierung
public class VulnerableAccountReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
// Anfällig: Keine Verifizierung der Intent-Quelle
if ("com.app.DELETE_ACCOUNT".equals(action)) {
String accountId = intent.getStringExtra("account_id");
// Jede App kann Konten löschen!
deleteAccount(context, accountId);
}
if ("com.app.SET_ADMIN".equals(action)) {
String userId = intent.getStringExtra("user_id");
// Jede App kann Admin-Privilegien gewähren!
setUserAsAdmin(context, userId);
}
}
}
// Anfällig: DNS-Cache ohne Quellenvalidierung
typedef struct {
char domain[256];
char ip_address[16];
time_t expiry;
} DNSCacheEntry;
DNSCacheEntry dns_cache[1000];
void vulnerable_process_dns_response(int socket, struct sockaddr_in *from) {
char buffer[512];
recv(socket, buffer, sizeof(buffer), 0);
DNSResponse *response = parse_dns_response(buffer);
// Anfällig: Keine Verifizierung, dass Antwort von legitimem DNS-Server kommt
// Angreifer kann gefälschte Antworten senden
for (int i = 0; i < response->answer_count; i++) {
// Cache mit Angreifer-IP vergiftet
add_to_cache(response->answers[i].domain,
response->answers[i].ip);
}
}
# Anfällig: Web-Service vertraut X-Forwarded-For
from flask import Flask, request
app = Flask(__name__)
ALLOWED_IPS = {'10.0.0.1', '10.0.0.2', '10.0.0.3'}
@app.route('/admin/action')
def vulnerable_admin_action():
# Anfällig: X-Forwarded-For kann leicht gefälscht werden
client_ip = request.headers.get('X-Forwarded-For', request.remote_addr)
# Angreifer fügt hinzu X-Forwarded-For: 10.0.0.1
if client_ip in ALLOWED_IPS:
perform_admin_action()
return "Aktion abgeschlossen"
return "Zugriff verweigert", 403
// Anfällig: PostMessage ohne Origin-Verifizierung
window.addEventListener('message', function(event) {
// Anfällig: Keine Verifizierung des Nachrichtenursprungs
var data = event.data;
if (data.action === 'updateCredentials') {
// Jede Website kann diese Nachricht senden!
updateStoredCredentials(data.username, data.password);
}
if (data.action === 'processPayment') {
// Jede Website kann Zahlung auslösen!
processPayment(data.amount, data.recipient);
}
});
Korrigierter Code
// Korrigiert: Android BroadcastReceiver mit Quellenverifizierung
public class FixedAccountReceiver extends BroadcastReceiver {
private static final String EXPECTED_PACKAGE = "com.mycompany.trustedapp";
@Override
public void onReceive(Context context, Intent intent) {
// Korrigiert: Intent-Quelle verifizieren
if (!isValidSource(context, intent)) {
Log.w(TAG, "Intent von unautorisierter Quelle abgelehnt");
return;
}
String action = intent.getAction();
if ("com.app.DELETE_ACCOUNT".equals(action)) {
String accountId = intent.getStringExtra("account_id");
deleteAccount(context, accountId);
}
}
private boolean isValidSource(Context context, Intent intent) {
// Korrigiert: Prüfen, ob dies ein impliziter Broadcast (vom System) ist
if (intent.getComponent() == null) {
return true; // System-Broadcast
}
// Für explizite Intents verifizieren, dass Sender Berechtigung hat
// Verwendung von Signaturebene-Berechtigung, die im Manifest definiert ist
String permission = "com.app.permission.ACCOUNT_MANAGEMENT";
if (context.checkCallingPermission(permission)
== PackageManager.PERMISSION_GRANTED) {
return true;
}
return false;
}
}
// AndroidManifest.xml:
// <permission
// android:name="com.app.permission.ACCOUNT_MANAGEMENT"
// android:protectionLevel="signature"/>
//
// <receiver android:name=".FixedAccountReceiver"
// android:exported="true"
// android:permission="com.app.permission.ACCOUNT_MANAGEMENT"/>
// Korrigiert: DNS-Cache mit Antwortvalidierung
#include <openssl/evp.h>
typedef struct {
struct sockaddr_in expected_server;
uint16_t expected_transaction_id;
char queried_domain[256];
} PendingQuery;
PendingQuery pending_queries[1000];
void fixed_process_dns_response(int socket, struct sockaddr_in *from) {
char buffer[512];
recv(socket, buffer, sizeof(buffer), 0);
DNSResponse *response = parse_dns_response(buffer);
// Korrigiert: Verifizieren, dass Antwortquelle unserer Abfrage entspricht
PendingQuery *query = find_pending_query(response->transaction_id);
if (!query) {
fprintf(stderr, "Unerwartete DNS-Antwort\n");
return;
}
// Korrigiert: Verifizieren, dass Antwort von erwartetem Server kommt
if (from->sin_addr.s_addr != query->expected_server.sin_addr.s_addr ||
from->sin_port != query->expected_server.sin_port) {
fprintf(stderr, "DNS-Antwort von unerwarteter Quelle\n");
return;
}
// Korrigiert: Verifizieren, dass Domain unserer Abfrage entspricht
if (strcmp(response->question.domain, query->queried_domain) != 0) {
fprintf(stderr, "DNS-Antwort-Domain stimmt nicht überein\n");
return;
}
// Korrigiert: DNSSEC-Validierung implementieren
if (!validate_dnssec_signatures(response)) {
fprintf(stderr, "DNSSEC-Validierung fehlgeschlagen\n");
return;
}
// Jetzt sicher zu cachen
for (int i = 0; i < response->answer_count; i++) {
add_to_cache(response->answers[i].domain,
response->answers[i].ip);
}
remove_pending_query(response->transaction_id);
}
# Korrigiert: Web-Service mit ordnungsgemäßer Quellenverifizierung
from flask import Flask, request
import hmac
import time
app = Flask(__name__)
ALLOWED_IPS = {'10.0.0.1', '10.0.0.2', '10.0.0.3'}
API_SECRET = b'shared_secret_key'
@app.route('/admin/action')
def fixed_admin_action():
# Korrigiert: Nicht allein auf IP verlassen
# Authentifizierungs-Token erforderlich
auth_token = request.headers.get('Authorization')
if not auth_token:
return "Fehlende Authentifizierung", 401
# HMAC-basiertes Token verifizieren
if not verify_auth_token(auth_token):
return "Ungültige Authentifizierung", 401
# Korrigiert: Wenn hinter bekanntem Proxy, IP als Defense-in-Depth validieren
if is_behind_trusted_proxy():
client_ip = request.headers.get('X-Forwarded-For', '').split(',')[0].strip()
else:
client_ip = request.remote_addr
if client_ip not in ALLOWED_IPS:
# Loggen, aber nicht unbedingt blockieren, wenn Auth gültig ist
app.logger.warning(f"Anfrage von unerwarteter IP: {client_ip}")
perform_admin_action()
return "Aktion abgeschlossen"
def verify_auth_token(token):
try:
# Token-Format: timestamp:signature
parts = token.split(':')
if len(parts) != 2:
return False
timestamp, signature = parts
# Timestamp-Aktualität prüfen (Replay verhindern)
if abs(time.time() - float(timestamp)) > 300:
return False
# Signatur verifizieren
expected = hmac.new(API_SECRET, timestamp.encode(), 'sha256').hexdigest()
return hmac.compare_digest(signature, expected)
except Exception:
return False
// Korrigiert: PostMessage mit Origin-Verifizierung
const TRUSTED_ORIGINS = [
'https://trusted-partner.com',
'https://app.mycompany.com'
];
window.addEventListener('message', function(event) {
// Korrigiert: Nachrichtenursprung verifizieren
if (!TRUSTED_ORIGINS.includes(event.origin)) {
console.warn('Nachricht von nicht vertrauenswürdigem Ursprung abgelehnt:', event.origin);
return;
}
var data = event.data;
// Korrigiert: Nachrichtenstruktur validieren
if (!data || typeof data.action !== 'string') {
return;
}
// Korrigiert: Erlaubte Aktionen pro Ursprung definieren
const allowedActions = {
'https://trusted-partner.com': ['updatePreferences', 'shareContent'],
'https://app.mycompany.com': ['updateCredentials', 'processPayment']
};
const originActions = allowedActions[event.origin] || [];
if (!originActions.includes(data.action)) {
console.warn('Aktion von diesem Ursprung nicht erlaubt:', data.action);
return;
}
switch (data.action) {
case 'updatePreferences':
updatePreferences(data.preferences);
break;
case 'processPayment':
// Zusätzliche Bestätigung für sensible Aktionen
confirmAndProcessPayment(data.amount, data.recipient);
break;
}
});
CVE-Beispiele
- CVE-2000-1218: DNS-Cache-Poisoning über nicht verifizierte Server-Updates.
- CVE-2005-0877: DNS-Resolver akzeptierte Antworten von unautorisierten Quellen.
- CVE-2001-1452: Caching von unautorisierten Glue-Records von nicht delegierten Nameservern.
Verwandte CWEs
- CWE-346: Origin Validation Error (Eltern)
- CWE-923: Improper Restriction of Communication Channel to Intended Endpoints (Eltern)
- CWE-925: Improper Verification of Intent by Broadcast Receiver (Kind)
- CWE-939: Improper Authorization in Handler for Custom URL Scheme (Kind)
Referenzen
- MITRE Corporation. "CWE-940: Improper Verification of Source of a Communication Channel." https://cwe.mitre.org/data/definitions/940.html
- OWASP. "Input Validation Cheat Sheet."
- RFC 5452. "Measures for Making DNS More Resilient against Forged Answers."