Verlass auf IP-Adresse für Authentifizierung

Beschreibung

Verlass auf IP-Adresse für Authentifizierung ist eine Schwachstelle, die auftritt, wenn ein Produkt eine IP-Adresse als einziges Mittel der Authentifizierung verwendet. IP-Adressen können leicht gespooft werden - Angreifer können Quell-IP-Adressen in Paketen fälschen, die sie senden. Während Antwortpakete an die gefälschte Adresse zurückkehren (was bidirektionale Kommunikation einschränkt), können sich Angreifer positionieren, um den Verkehr zwischen dem Opfer und der gespooften IP-Adresse abzufangen. Obwohl Source-Routing-Mechanismen Subnetz-Positionierungsanforderungen umgehen könnten, sind sie im Internet weitgehend deaktiviert. Das grundlegende Problem ist, dass IP-Adressen nie als Authentifizierungsanmeldedaten konzipiert wurden und keinen kryptografischen Identitätsnachweis bieten.

Risiko

Die Verwendung von IP-Adressen für Authentifizierung bietet im Wesentlichen keine echte Sicherheit gegen motivierte Angreifer. In lokalen Netzwerken ermöglicht ARP-Spoofing Angreifern, Verkehr umzuleiten und jede IP-Adresse zu imitieren. In weiteren Netzwerken kann blindes IP-Spoofing für verbindungslose Protokolle wie UDP effektiv sein, bei denen Angreifer keine Antworten empfangen müssen. Selbst für TCP können Angreifer im selben Netzwerksegment andere Hosts vollständig imitieren. Das Risiko ist besonders schwerwiegend für administrative Schnittstellen, Datenbankzugriff und API-Endpunkte, die sich ausschließlich auf IP-Allowlists verlassen. Angreifer, die ein beliebiges System in einem vertrauenswürdigen Netzwerksegment kompromittieren, erlangen sofort Zugang zu allen IP-authentifizierten Ressourcen. Cloud-Umgebungen und containerisierte Bereitstellungen verkomplizieren IP-basiertes Vertrauen weiter, da IP-Adressen kurzlebig sind und neu zugewiesen werden können.

Lösung

Verwenden Sie IP-Adressverifikation als ergänzende Sicherheitsschicht, aber nie als einzelnen Authentifizierungsfaktor. Implementieren Sie ordnungsgemäße Authentifizierungsmechanismen, die nicht gespooft werden können: Benutzername/Passwort-Kombinationen mit sicherer Übertragung (TLS), digitale Zertifikate mit ordnungsgemäßer Validierung, API-Schlüssel mit kryptografischen Signaturen oder Multi-Faktor-Authentifizierung. Für interne Dienste verwenden Sie gegenseitiges TLS (mTLS), bei dem sowohl Client als auch Server Zertifikate präsentieren. Wenn IP-Beschränkungen für Compliance oder Defense-in-Depth erforderlich sind, kombinieren Sie sie mit stärker Authentifizierung. Erwägen Sie Netzwerksegmentierung und Zero-Trust-Architekturen, bei denen alle Anfragen unabhängig vom Quellnetzwerk Authentifizierung erfordern. Für sensible Operationen implementieren Sie zusätzliche Verifikation über Netzwerkebenenkontrollen hinaus.

Häufige Auswirkungen

AuswirkungDetails
Zugriffskontrolle, Non-RepudiationBereich: Zugriffskontrolle, Non-Repudiation

Böswillige Benutzer können Authentifizierungsinformationen fälschen, indem sie IP-Adressen spoofen und jeden Host imitieren. Dies ermöglicht unbefugten Zugang zu geschützten Ressourcen und unterbricht Audit-Trails, da Aktionen der gespooften Adresse zugeschrieben werden anstatt dem Angreifer.

Beispielcode

Anfälliger Code (C)

Die folgenden Beispiele demonstrieren den Verlass auf IP-Adresse für Authentifizierung:

// Anfällig: Nur-IP-Authentifizierung für Dienstzugang
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <string.h>

#define TRUSTED_IP "192.168.1.100"

int vulnerable_check_auth(int client_socket) {
    struct sockaddr_in client_addr;
    socklen_t addr_len = sizeof(client_addr);

    getpeername(client_socket, (struct sockaddr *)&client_addr, &addr_len);

    // Anfällig: Authentifizierung basiert ausschließlich auf IP
    char *client_ip = inet_ntoa(client_addr.sin_addr);

    if (strcmp(client_ip, TRUSTED_IP) == 0) {
        return 1;  // Authentifiziert!
        // Angreifer spooft IP um Zugang zu erlangen
    }

    return 0;
}

void vulnerable_service(int server_socket) {
    while (1) {
        int client = accept(server_socket, NULL, NULL);

        if (vulnerable_check_auth(client)) {
            // Gewährt vollen Zugang basierend nur auf IP
            handle_privileged_request(client);
        } else {
            close(client);
        }
    }
}
// Anfällig: Java-Dienst mit IP-basierter Authentifizierung
import java.net.*;

public class VulnerableIPAuth {

    private static final String[] TRUSTED_IPS = {
        "10.0.0.1", "10.0.0.2", "192.168.1.100"
    };

    public boolean authenticate(Socket connection) {
        // Anfällig: Prüft nur IP-Adresse
        String clientIP = connection.getInetAddress().getHostAddress();

        for (String trusted : TRUSTED_IPS) {
            if (trusted.equals(clientIP)) {
                return true;  // Spoofbar!
            }
        }

        return false;
    }

    public void handleConnection(Socket conn) {
        if (authenticate(conn)) {
            // Voller privilegierter Zugang basierend auf IP
            processAdminRequest(conn);
        }
    }
}
# Anfällig: Web-API mit nur IP-Allowlist
from flask import Flask, request

app = Flask(__name__)

ALLOWED_IPS = ['10.0.0.1', '192.168.1.100', '172.16.0.5']

@app.route('/admin/api')
def vulnerable_admin_api():
    # Anfällig: Nur-IP-Authentifizierung
    client_ip = request.remote_addr

    if client_ip in ALLOWED_IPS:
        return perform_admin_action()
    # Angreifer im selben Netzwerksegment kann IP spoofen

    return "Zugriff verweigert", 403

Korrigierter Code (C)

// Korrigiert: Ordnungsgemäße Authentifizierung mit IP als ergänzende Prüfung
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <string.h>
#include <openssl/ssl.h>

typedef struct {
    char *api_key;
    char *signature;
    long timestamp;
} AuthCredentials;

int verify_credentials(AuthCredentials *creds) {
    // Verifizieren, dass API-Schlüssel existiert und gültig ist
    if (!is_valid_api_key(creds->api_key)) {
        return 0;
    }

    // Signatur verifizieren
    if (!verify_hmac_signature(creds->api_key, creds->signature, creds->timestamp)) {
        return 0;
    }

    // Zeitstempel prüfen um Replay zu verhindern
    if (abs(time(NULL) - creds->timestamp) > MAX_TIMESTAMP_SKEW) {
        return 0;
    }

    return 1;
}

int secure_check_auth(SSL *ssl, int client_socket) {
    // Korrigiert: Ordnungsgemäße Anmeldedaten erfordern
    AuthCredentials creds;
    if (!receive_credentials(ssl, &creds)) {
        return 0;
    }

    if (!verify_credentials(&creds)) {
        return 0;
    }

    // IP-Prüfung als zusätzliche Schicht (Defense in Depth)
    struct sockaddr_in client_addr;
    socklen_t addr_len = sizeof(client_addr);
    getpeername(client_socket, (struct sockaddr *)&client_addr, &addr_len);
    char *client_ip = inet_ntoa(client_addr.sin_addr);

    if (!is_ip_in_allowed_range(client_ip)) {
        log_warning("Gültige Anmeldedaten von unerwarteter IP: %s", client_ip);
        // Könnte zusätzliche Verifikation erfordern, aber Anmeldedaten sind primär
    }

    return 1;
}
// Korrigiert: Java-Dienst mit ordnungsgemäßer Authentifizierung
import javax.net.ssl.*;
import java.security.*;

public class SecureAuth {

    private final TokenValidator tokenValidator;

    public AuthResult authenticate(SSLSocket connection) {
        // Korrigiert: Client-Zertifikat verifizieren (gegenseitiges TLS)
        try {
            SSLSession session = connection.getSession();
            Certificate[] certs = session.getPeerCertificates();

            if (certs == null || certs.length == 0) {
                return AuthResult.failure("Kein Client-Zertifikat");
            }

            X509Certificate clientCert = (X509Certificate) certs[0];

            // Verifizieren, dass Zertifikat gültig und vertrauenswürdig ist
            if (!verifyCertificate(clientCert)) {
                return AuthResult.failure("Ungültiges Zertifikat");
            }

            // Identität aus Zertifikat extrahieren
            String clientId = extractClientId(clientCert);

            // IP kann für Auditing protokolliert werden
            String clientIP = connection.getInetAddress().getHostAddress();
            auditLog.record("auth_success", clientId, clientIP);

            return AuthResult.success(clientId);

        } catch (SSLPeerUnverifiedException e) {
            return AuthResult.failure("Zertifikatsverifikation fehlgeschlagen");
        }
    }

    // Alternative: Token-basierte Authentifizierung
    public AuthResult authenticateByToken(String authHeader) {
        if (authHeader == null || !authHeader.startsWith("Bearer ")) {
            return AuthResult.failure("Autorisierung fehlt");
        }

        String token = authHeader.substring(7);

        if (!tokenValidator.isValid(token)) {
            return AuthResult.failure("Ungültiges Token");
        }

        return AuthResult.success(tokenValidator.getIdentity(token));
    }
}
# Korrigiert: Web-API mit ordnungsgemäßer Authentifizierung
from flask import Flask, request, abort
from functools import wraps
import jwt
import hmac
import hashlib
import time

app = Flask(__name__)

def require_auth(f):
    """Korrigiert: Ordnungsgemäße token-basierte Authentifizierung"""
    @wraps(f)
    def decorated(*args, **kwargs):
        auth_header = request.headers.get('Authorization')

        if not auth_header or not auth_header.startswith('Bearer '):
            abort(401, 'Autorisierung fehlt')

        token = auth_header.split(' ')[1]

        try:
            # JWT-Token verifizieren
            payload = jwt.decode(token, SECRET_KEY, algorithms=['HS256'])

            # Ablauf prüfen
            if payload.get('exp', 0) < time.time():
                abort(401, 'Token abgelaufen')

            request.user = payload

        except jwt.InvalidTokenError:
            abort(401, 'Ungültiges Token')

        return f(*args, **kwargs)
    return decorated

def verify_api_signature(f):
    """Alternative: HMAC-Signaturverifikation"""
    @wraps(f)
    def decorated(*args, **kwargs):
        api_key = request.headers.get('X-API-Key')
        signature = request.headers.get('X-Signature')
        timestamp = request.headers.get('X-Timestamp')

        if not all([api_key, signature, timestamp]):
            abort(401, 'Authentifizierungs-Header fehlen')

        # Zeitstempel-Aktualität verifizieren
        if abs(time.time() - int(timestamp)) > 300:
            abort(401, 'Anfrage abgelaufen')

        # Signatur verifizieren
        secret = get_secret_for_api_key(api_key)
        if not secret:
            abort(401, 'Ungültiger API-Schlüssel')

        expected = hmac.new(
            secret.encode(),
            f"{timestamp}{request.path}".encode(),
            hashlib.sha256
        ).hexdigest()

        if not hmac.compare_digest(signature, expected):
            abort(401, 'Ungültige Signatur')

        return f(*args, **kwargs)
    return decorated

@app.route('/admin/api')
@require_auth
def secure_admin_api():
    # IP protokolliert für Auditing, nicht für Auth verwendet
    client_ip = request.remote_addr
    app.logger.info(f"Admin-API-Zugriff durch {request.user['id']} von {client_ip}")

    return perform_admin_action()

Die Korrektur ersetzt IP-basierte Authentifizierung durch ordnungsgemäße Anmeldedatenverifikation (Token, Zertifikate, signierte Anfragen) und behält IP-Prüfungen nur als ergänzende Audit- oder Defense-in-Depth-Maßnahme bei.


Ausgenutzt in der Praxis

Hausautomations-IP-Allowlist-Umgehung (IoT, 2022)

CVE-2022-30319 dokumentierte die S-Bus-Funktionalität eines Hausautomationsprodukts, die IP-Allowlisting für Zugriffskontrolle verwendete. Angreifer umgingen dies durch IP-Adress-Spoofing und erlangten unbefugte Kontrolle über Hausautomationssysteme.

Datenbankzugriff via IP-Spoofing (Unternehmenssysteme, Fortlaufend)

Datenbanksysteme, die mit IP-basierten Zugriffskontrollen konfiguriert waren, wurden kompromittiert, als Angreifer Zugang zu vertrauenswürdigen Netzwerksegmenten erlangten und autorisierte IP-Adressen spooften, um auf sensible Daten zuzugreifen.

Interne API-Ausnutzung (Cloud-Umgebungen, Fortlaufend)

Cloud-Dienste, die IP-Allowlists für interne APIs verwenden, wurden ausgenutzt, als Angreifer eine beliebige Instanz im vertrauenswürdigen IP-Bereich kompromittierten und Zugang zu allen IP-authentifizierten Diensten erlangten.


Tools zum Testen/Ausnutzen

  • hping3 — Netzwerktool, das Pakete mit gespooften Quelladressen senden kann.

  • Scapy — Python-Paketmanipulationsbibliothek für IP-Spoofing-Tests.

  • arpspoof — ARP-Spoofing-Tool für lokale Netzwerkangriffe.


CVE-Beispiele

  • CVE-2022-30319 — S-Bus-Funktionalität eines Hausautomationsprodukts verwendete IP-Allowlisting, das Angreifer durch IP-Adressfälschung umgingen.

Referenzen

  1. MITRE Corporation. "CWE-291: Reliance on IP Address for Authentication." Common Weakness Enumeration. https://cwe.mitre.org/data/definitions/291.html

  2. OWASP Foundation. "Authentication Cheat Sheet." https://cheatsheetseries.owasp.org/cheatsheets/Authentication_Cheat_Sheet.html

  3. NIST. "Zero Trust Architecture." SP 800-207. https://csrc.nist.gov/publications/detail/sp/800-207/final