Verwendung einer weniger vertrauenswürdigen Quelle
Beschreibung
Verwendung einer weniger vertrauenswürdigen Quelle ist eine Schwachstelle, die auftritt, wenn ein Produkt zwischen mehreren Datenquellen auswählt, aber diejenige wählt, die reduzierte Verifizierungsfähigkeit, verminderte Vertrauenswürdigkeit oder erhöhte Anfälligkeit für Kompromittierung bietet. Dies manifestiert sich häufig, wenn Anwendungen client-gelieferten Daten mehr vertrauen als server-verifizierten Informationen, wie z.B. dem X-Forwarded-For HTTP-Header anstelle der tatsächlichen Verbindungs-IP-Adresse zu vertrauen, oder client-bereitgestellter Benutzeridentität anstelle von serverseitigen Authentifizierungsdaten zu vertrauen. Die Schwachstelle entsteht durch Priorisierung von Bequemlichkeit oder Kompatibilität über Sicherheit, wenn mehrere Informationsquellen unterschiedlicher Vertrauenswürdigkeit verfügbar sind. Die gewählte weniger vertrauenswürdige Quelle kann von Angreifern manipuliert werden, um Sicherheitskontrollen zu umgehen, Identitäten zu fälschen oder bösartige Daten zu injizieren.
Risiko
Das Vertrauen in weniger zuverlässige Datenquellen erzeugt Sicherheits-Bypasses, die Angreifer ausnutzen können, um Authentifizierungs-, Autorisierungs- und Audit-Kontrollen zu umgehen. Wenn Anwendungen X-Forwarded-For-Headern für IP-basierte Zugriffskontrolle vertrauen, können Angreifer interne IP-Adressen fälschen, um Firewall-Beschränkungen zu umgehen und auf nur intern zugängliche Ressourcen zuzugreifen. Client-gelieferte Identitätsinformationen können für Session-Hijacking oder Privilegien-Eskalation manipuliert werden. Audit-Logs, die auf fälschbaren Daten basieren, werden für forensische Analyse und Incident Response unzuverlässig. IP-basiertes Rate-Limiting mit gefälschten Headern ermöglicht Angreifern, Missbrauchsschutz zu umgehen. Geografische Beschränkungen basierend auf gefälschten Standortdaten können umgangen werden. Das Risiko ist besonders schwerwiegend, wenn die weniger vertrauenswürdige Quelle für sicherheitskritische Entscheidungen wie Zugriffskontrolle, Authentifizierung oder Audit-Logging verwendet wird, da Angreifer sowohl bösartige Aktionen durchführen als auch ihre wahre Identität verbergen können.
Lösung
Bevorzugen Sie immer die vertrauenswürdigste Datenquelle, wenn mehrere Quellen verfügbar sind. Für IP-Adressen verwenden Sie die direkte Verbindungs-IP (REMOTE_ADDR) anstelle von Headern wie X-Forwarded-For, die gefälscht werden können. Wenn Proxy-Header verwendet werden müssen, vertrauen Sie ihnen nur von bekannten Proxy-Servern, indem Sie zuerst die direkte Verbindungs-IP validieren. Implementieren Sie eine Vertrauenskette, bei der jeder Hop in einer Proxy-Kette verifiziert wird. Für Benutzeridentität verwenden Sie immer serverseitige Session-Daten anstelle von client-gelieferten Werten. Dokumentieren Sie die Vertrauensstufe jeder Datenquelle und stellen Sie sicher, dass Sicherheitsentscheidungen angemessen vertrauenswürdige Quellen verwenden. Wenn Client-Daten verwendet werden müssen, validieren Sie sie gegen serverseitige Aufzeichnungen. Implementieren Sie Logging, das sowohl vertrauenswürdige als auch nicht vertrauenswürdige Werte erfasst, um forensische Analyse zu unterstützen.
Häufige Auswirkungen
| Auswirkung | Details |
|---|---|
| Zugriffskontrolle | Umfang: Zugriffskontrolle Angreifer können IP-basierte Zugriffsbeschränkungen, Authentifizierungsprüfungen und Autorisierungskontrollen umgehen, indem sie gefälschte Werte über die weniger vertrauenswürdige Quelle liefern. |
| Integrität | Umfang: Integrität Audit-Logs und Sicherheitsaufzeichnungen werden unzuverlässig, wenn sie angreifer-kontrollierte Daten aus weniger vertrauenswürdigen Quellen enthalten, was Incident Response und Forensik kompromittiert. |
| Nicht-Abstreitbarkeit | Umfang: Nicht-Abstreitbarkeit Angreifer können ihre wahre Identität verbergen, indem sie Daten in weniger vertrauenswürdigen Quellen fälschen, was es schwierig macht, bösartige Aktionen ihrer tatsächlichen Quelle zuzuordnen. |
Beispielcode
Anfälliger Code (PHP/Python)
Die folgenden Beispiele demonstrieren die Verwendung weniger vertrauenswürdiger Quellen:
<?php
// Anfällig: Verwendung des weniger vertrauenswürdigen X-Forwarded-For Headers
// Anfällig: X-Forwarded-For für Zugriffskontrolle vertrauen
function vulnerable_check_internal_access() {
// Anfällig: Bevorzugt X-Forwarded-For gegenüber REMOTE_ADDR
if (isset($_SERVER['HTTP_X_FORWARDED_FOR'])) {
$client_ip = $_SERVER['HTTP_X_FORWARDED_FOR'];
} else {
$client_ip = $_SERVER['REMOTE_ADDR'];
}
// Anfällig: IP-basierte Zugriffskontrolle auf fälschbarem Header
return strpos($client_ip, '10.') === 0 ||
strpos($client_ip, '192.168.') === 0;
}
// Anfällig: Rate-Limiting mit fälschbarer IP
function vulnerable_rate_limit() {
// Anfällig: Client-gelieferter IP vertrauen
$ip = $_SERVER['HTTP_X_FORWARDED_FOR'] ?? $_SERVER['REMOTE_ADDR'];
$key = "rate_limit_" . $ip;
$count = cache_get($key) ?? 0;
if ($count > 100) {
http_response_code(429);
exit("Ratenlimit überschritten");
}
cache_set($key, $count + 1, 60);
}
// Anfällig: Logging mit fälschbaren Daten
function vulnerable_log_action($action) {
// Anfällig: Angreifer-kontrollierte IP loggen
$ip = $_SERVER['HTTP_X_FORWARDED_FOR'] ?? $_SERVER['REMOTE_ADDR'];
// Audit-Log für Forensik unzuverlässig
log_to_file("Aktion: $action von IP: $ip");
}
// Anfällig: Client-gelieferter Benutzeridentität vertrauen
function vulnerable_get_user_id() {
// Anfällig: Client-Cookie gegenüber Session vertrauen
if (isset($_COOKIE['user_id'])) {
return $_COOKIE['user_id'];
}
return $_SESSION['user_id'] ?? null;
}
// Anfällig: Geografische Beschränkung umgehbar
function vulnerable_geo_restriction() {
// Anfällig: CF-IPCountry Header vertrauen
$country = $_SERVER['HTTP_CF_IPCOUNTRY'] ?? 'XX';
// Angreifer kann diesen Header fälschen
if (in_array($country, ['US', 'CA', 'UK'])) {
return true;
}
return false;
}
?>
# Anfällig: Verwendung weniger vertrauenswürdiger Quellen in Python
from flask import Flask, request
app = Flask(__name__)
# Anfällig: X-Forwarded-For für IP vertrauen
def vulnerable_get_client_ip():
# Anfällig: Bevorzugt fälschbaren Header gegenüber tatsächlicher Verbindungs-IP
forwarded_for = request.headers.get('X-Forwarded-For')
if forwarded_for:
# Anfällig: Erste IP aus Header nehmen (angreifer-kontrolliert)
return forwarded_for.split(',')[0].strip()
return request.remote_addr
# Anfällig: Zugriffskontrolle mit gefälschter IP
@app.route('/admin')
def vulnerable_admin_access():
client_ip = vulnerable_get_client_ip()
# Anfällig: IP-basierte Zugriffskontrolle auf nicht vertrauenswürdigen Daten
if not client_ip.startswith('10.') and not client_ip.startswith('192.168.'):
return "Zugriff verweigert", 403
return render_admin_panel()
# Anfällig: Client-gelieferter Rolle vertrauen
@app.route('/api/action')
def vulnerable_role_check():
# Anfällig: Rolle aus Request statt Session vertrauen
user_role = request.headers.get('X-User-Role', 'user')
if user_role == 'admin':
return perform_admin_action()
return perform_user_action()
# Anfällig: Authentifizierung mit weniger vertrauenswürdiger Quelle
@app.route('/api/data')
def vulnerable_auth():
# Anfällig: JWT aus Cookie gegenüber Session vertrauen
jwt_token = request.cookies.get('auth_token')
session_user = session.get('user_id')
# Anfällig: Bevorzugt client-kontrolliertes Cookie
if jwt_token:
user = decode_jwt_without_verification(jwt_token)
return get_user_data(user['id'])
elif session_user:
return get_user_data(session_user)
return "Nicht authentifiziert", 401
# Anfällig: Rate-Limiting mit gefälschter Identität
from functools import wraps
def vulnerable_rate_limit(f):
@wraps(f)
def decorated(*args, **kwargs):
# Anfällig: Fälschbaren Header für Rate-Limit-Schlüssel verwenden
client_id = request.headers.get('X-Client-ID',
vulnerable_get_client_ip())
key = f"rate:{client_id}"
count = redis.incr(key)
if count == 1:
redis.expire(key, 60)
if count > 100:
return "Ratenlimit überschritten", 429
return f(*args, **kwargs)
return decorated
// Anfällig: Verwendung weniger vertrauenswürdiger Quellen in Java
import javax.servlet.http.*;
public class VulnerableTrustSource extends HttpServlet {
// Anfällig: IP aus Header statt Verbindung
private String vulnerableGetClientIP(HttpServletRequest request) {
// Anfällig: Bevorzugt fälschbaren Header
String forwardedFor = request.getHeader("X-Forwarded-For");
if (forwardedFor != null && !forwardedFor.isEmpty()) {
return forwardedFor.split(",")[0].trim();
}
return request.getRemoteAddr();
}
// Anfällig: Zugriffskontrolle mit gefälschter IP
@Override
protected void doGet(HttpServletRequest request,
HttpServletResponse response) {
String clientIP = vulnerableGetClientIP(request);
// Anfällig: Sicherheitsentscheidung auf nicht vertrauenswürdigen Daten
if (!clientIP.startsWith("10.") && !clientIP.startsWith("192.168.")) {
response.setStatus(403);
return;
}
serveAdminContent(response);
}
// Anfällig: Benutzeridentität aus Header
private String vulnerableGetUserId(HttpServletRequest request) {
// Anfällig: Client-geliefertem Header gegenüber Session vertrauen
String headerUserId = request.getHeader("X-User-Id");
if (headerUserId != null) {
return headerUserId; // Angreifer-kontrolliert!
}
HttpSession session = request.getSession(false);
return session != null ? (String) session.getAttribute("userId") : null;
}
// Anfällig: Logging mit gefälschten Daten
private void vulnerableAuditLog(HttpServletRequest request, String action) {
String clientIP = vulnerableGetClientIP(request);
String userId = vulnerableGetUserId(request);
// Anfällig: Log enthält angreifer-kontrollierte Daten
logger.info("Aktion: {} von Benutzer {} von IP {}", action, userId, clientIP);
}
// Anfällig: Geografische Beschränkung
private boolean vulnerableCheckGeo(HttpServletRequest request) {
// Anfällig: CloudFlare-Header ohne Verifizierung vertrauen
String country = request.getHeader("CF-IPCountry");
if (country == null) {
country = "XX";
}
// Angreifer kann diesen Header hinzufügen
return Arrays.asList("US", "CA", "UK").contains(country);
}
}
Korrigierter Code (PHP/Python)
<?php
// Korrigiert: Verwendung vertrauenswürdiger Datenquellen
// Korrigiert: Nur Proxy-Headern von bekannten Proxies vertrauen
function secure_get_client_ip() {
// Korrigiert: Liste vertrauenswürdiger Proxy-IPs
$trusted_proxies = ['10.0.0.1', '10.0.0.2']; // Load-Balancer-IPs
// Korrigiert: Immer mit REMOTE_ADDR beginnen (nicht fälschbar)
$remote_addr = $_SERVER['REMOTE_ADDR'];
// Korrigiert: Nur X-Forwarded-For vertrauen wenn Request von vertrauenswürdigem Proxy
if (in_array($remote_addr, $trusted_proxies) &&
isset($_SERVER['HTTP_X_FORWARDED_FOR'])) {
// Korrigiert: Kette ordnungsgemäß parsen
$chain = array_map('trim', explode(',', $_SERVER['HTTP_X_FORWARDED_FOR']));
// Korrigiert: Rechteste nicht vertrauenswürdige IP zurückgeben
// (letzte IP vor unserer vertrauenswürdigen Proxy-Kette)
return $chain[0];
}
// Korrigiert: Standard auf tatsächliche Verbindungs-IP
return $remote_addr;
}
// Korrigiert: Zugriffskontrolle mit vertrauenswürdiger IP
function secure_check_internal_access() {
$client_ip = secure_get_client_ip();
// Korrigiert: Vertrauenswürdige IP-Quelle verwenden
return strpos($client_ip, '10.') === 0 ||
strpos($client_ip, '192.168.') === 0;
}
// Korrigiert: Rate-Limiting mit vertrauenswürdiger Identität
function secure_rate_limit() {
// Korrigiert: Vertrauenswürdige IP-Quelle verwenden
$ip = secure_get_client_ip();
// Korrigiert: Zusätzlich authentifizierte Benutzer-ID verwenden falls verfügbar
$user_id = $_SESSION['user_id'] ?? null;
$key = $user_id ? "rate_limit_user_$user_id" : "rate_limit_ip_$ip";
$count = cache_get($key) ?? 0;
if ($count > 100) {
http_response_code(429);
exit("Ratenlimit überschritten");
}
cache_set($key, $count + 1, 60);
}
// Korrigiert: Logging mit vertrauenswürdigen und nicht vertrauenswürdigen Daten
function secure_log_action($action) {
// Korrigiert: Vertrauenswürdige IP loggen
$trusted_ip = secure_get_client_ip();
// Korrigiert: Auch nicht vertrauenswürdig für Forensik loggen (klar markiert)
$forwarded_for = $_SERVER['HTTP_X_FORWARDED_FOR'] ?? 'keine';
// Korrigiert: Klare Unterscheidung zwischen vertrauenswürdig und nicht vertrauenswürdig
log_to_file(sprintf(
"Aktion: %s | Vertrauenswürdige IP: %s | X-Forwarded-For (nicht vertrauenswürdig): %s",
$action, $trusted_ip, $forwarded_for
));
}
// Korrigiert: Benutzeridentität nur aus Session
function secure_get_user_id() {
// Korrigiert: Nur serverseitiger Session vertrauen
if (!isset($_SESSION['user_id'])) {
return null;
}
return $_SESSION['user_id'];
// Korrigiert: Niemals client-gelieferter Benutzer-ID vertrauen
}
// Korrigiert: Geografische Beschränkung mit Verifizierung
function secure_geo_restriction() {
// Korrigiert: Vertrauenswürdige Client-IP holen
$client_ip = secure_get_client_ip();
// Korrigiert: Serverseitige Geo-Abfrage durchführen
$country = geoip_country_code($client_ip); // Serverseitige Abfrage
if (in_array($country, ['US', 'CA', 'UK'])) {
return true;
}
return false;
}
?>
# Korrigiert: Verwendung vertrauenswürdiger Datenquellen in Python
from flask import Flask, request, session
import ipaddress
app = Flask(__name__)
# Korrigiert: Konfiguration für vertrauenswürdige Proxies
TRUSTED_PROXIES = {'10.0.0.1', '10.0.0.2'} # Load-Balancer-IPs
INTERNAL_NETWORKS = [
ipaddress.ip_network('10.0.0.0/8'),
ipaddress.ip_network('192.168.0.0/16'),
ipaddress.ip_network('172.16.0.0/12')
]
# Korrigiert: Vertrauenswürdige IP-Extraktion
def secure_get_client_ip():
remote_addr = request.remote_addr
# Korrigiert: Nur Proxy-Headern von bekannten Proxies vertrauen
if remote_addr in TRUSTED_PROXIES:
forwarded_for = request.headers.get('X-Forwarded-For')
if forwarded_for:
# Korrigiert: Erste (Client) IP aus Kette holen
client_ip = forwarded_for.split(',')[0].strip()
try:
# Korrigiert: Validieren dass es eine gültige IP ist
ipaddress.ip_address(client_ip)
return client_ip
except ValueError:
pass # Ungültige IP, auf remote_addr zurückfallen
# Korrigiert: Standard auf direkte Verbindungs-IP
return remote_addr
# Korrigiert: Zugriffskontrolle mit vertrauenswürdiger IP
@app.route('/admin')
def secure_admin_access():
client_ip = secure_get_client_ip()
try:
ip_obj = ipaddress.ip_address(client_ip)
# Korrigiert: Gegen interne Netzwerke mit vertrauenswürdiger IP prüfen
is_internal = any(ip_obj in net for net in INTERNAL_NETWORKS)
if not is_internal:
return "Zugriff verweigert", 403
return render_admin_panel()
except ValueError:
return "Ungültige Anfrage", 400
# Korrigiert: Rolle nur aus Session
@app.route('/api/action')
def secure_role_check():
# Korrigiert: Nur Session-Daten für Rolle vertrauen
if 'user' not in session:
return "Nicht authentifiziert", 401
user_role = session['user']['role'] # Aus serverseitiger Session
if user_role == 'admin':
return perform_admin_action()
return perform_user_action()
# Korrigiert: Authentifizierung mit vertrauenswürdiger Quelle
@app.route('/api/data')
def secure_auth():
# Korrigiert: Nur serverseitiger Session vertrauen
if 'user_id' not in session:
return "Nicht authentifiziert", 401
user_id = session['user_id'] # Server-verifiziert
return get_user_data(user_id)
# Korrigiert: Rate-Limiting mit vertrauenswürdiger Identität
from functools import wraps
def secure_rate_limit(f):
@wraps(f)
def decorated(*args, **kwargs):
# Korrigiert: Vertrauenswürdige Identität für Rate-Limiting verwenden
if 'user_id' in session:
# Authentifizierte Benutzer: Rate-Limit nach Benutzer-ID
key = f"rate:user:{session['user_id']}"
else:
# Anonym: Rate-Limit nach vertrauenswürdiger IP
key = f"rate:ip:{secure_get_client_ip()}"
count = redis.incr(key)
if count == 1:
redis.expire(key, 60)
if count > 100:
return "Ratenlimit überschritten", 429
return f(*args, **kwargs)
return decorated
# Korrigiert: Logging mit Vertrauensstufen
import logging
def secure_audit_log(action):
trusted_ip = secure_get_client_ip()
user_id = session.get('user_id', 'anonym')
# Korrigiert: Vertrauensstufe der Daten klar markieren
untrusted_xff = request.headers.get('X-Forwarded-For', 'keine')
logging.info(
f"AUDIT | action={action} | "
f"trusted_ip={trusted_ip} | "
f"user_id={user_id} | "
f"xff_untrusted={untrusted_xff}"
)
Die Korrektur stellt sicher, dass Sicherheitsentscheidungen die vertrauenswürdigste verfügbare Datenquelle verwenden, mit ordnungsgemäßer Validierung von Proxy-Ketten.
Ausgenutzt in der Praxis
X-Forwarded-For Spoofing (CVE-2001-0860)
Anwendung verließ sich auf client-gelieferte IP anstelle von Paket-Headern, was Angreifern ermöglichte, IP-basierte Zugriffskontrollen zu umgehen.
PHP-Anwendung Header-Vertrauen (CVE-2006-1126)
PHP-Anwendung vertraute X-Forwarded-For anstelle von REMOTE_ADDR, was Zugriffskontroll-Bypass ermöglichte.
Tools zum Testen/Ausnutzen
-
Burp Suite — HTTP-Header modifizieren um X-Forwarded-For Spoofing zu testen.
-
curl — Anfragen mit benutzerdefinierten Headern zum Testen senden.
-
OWASP ZAP — Automatisiertes Scannen nach Header-Injection-Schwachstellen.
CVE-Beispiele
-
CVE-2001-0860 — Client-gelieferter IP gegenüber Paket-Headern vertraut.
-
CVE-2004-1950 — X-Forwarded-For gegenüber Server-Variablen priorisiert.
-
CVE-2006-1126 — PHP vertraute X-Forwarded-For für Zugriffskontrolle.
Referenzen
-
MITRE Corporation. "CWE-348: Use of Less Trusted Source." Common Weakness Enumeration. https://cwe.mitre.org/data/definitions/348.html
-
OWASP Foundation. "HTTP Request Smuggling." https://owasp.org/www-community/attacks/HTTP_Request_Smuggling
-
Mozilla Developer Network. "X-Forwarded-For." https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Forwarded-For