Server-Side Request Forgery (SSRF)

Beschreibung

Server-Side Request Forgery (SSRF) tritt auf, wenn eine Webanwendung eine Remote-Ressource abruft, ohne die vom Benutzer bereitgestellte URL zu validieren. Dies ermöglicht es Angreifern, die Anwendung zu zwingen, Anfragen an ein unerwartetes Ziel zu senden, selbst wenn es durch eine Firewall, ein VPN oder eine Netzwerk-Zugriffskontrollliste geschützt ist. Angreifer können SSRF missbrauchen, um auf interne Dienste, Cloud-Metadaten-Endpunkte zuzugreifen, lokale Dateien zu lesen (mit dem file://-Protokoll), interne Netzwerke zu scannen oder mit internen APIs zu interagieren. SSRF ist mit Cloud-Deployments zunehmend kritisch geworden, da Metadaten-Dienste sensible Anmeldedaten enthalten.

Risiko

SSRF ist in den CWE Top 25 und OWASP Top 10 aufgeführt. CVE-2024-43394 im Apache HTTP Server ermöglicht SSRF, das SMB-Verbindungen zu angreifergesteuerten Hosts auslöst und NTLM-Authentifizierungs-Hashes für Offline-Cracking oder Relay-Angriffe erfasst. CVE-2025-59775 im Apache HTTP Server ermöglicht SSRF, wenn AllowEncodedSlashes aktiviert ist. CVE-2025-47437 in LiteSpeed Cache ermöglicht authentifizierten Benutzern, serverseitige Anfragen an interne Ressourcen zu stellen. Der Capital-One-Breach nutzte SSRF aus, um auf AWS-Metadaten-Dienste zuzugreifen und über 100 Millionen Datensätze offenzulegen. Tesla-Cryptojacking-Vorfälle nutzten SSRF, um auf interne Cloud-Infrastruktur zuzugreifen.

Lösung

Validieren und sanitisieren Sie alle vom Benutzer bereitgestellten URLs. Implementieren Sie Allowlists für erlaubte Domains und Protokolle. Blockieren Sie Anfragen an private IP-Bereiche (10.x.x.x, 172.16-31.x.x, 192.168.x.x, 127.x.x.x, 169.254.x.x). Deaktivieren Sie unnötige URL-Schemata (file://, gopher://, dict://). Verwenden Sie DNS-Auflösungsvalidierung, um DNS-Rebinding zu verhindern. Implementieren Sie Netzwerksegmentierung, um die SSRF-Auswirkungen zu begrenzen. Blockieren Sie den Zugriff auf Cloud-Metadaten-Endpunkte (169.254.169.254). Verwenden Sie IMDSv2 auf AWS, das Session-Tokens erfordert. Überwachen Sie ungewöhnliche ausgehende Verbindungen.

Häufige Auswirkungen

AuswirkungDetails
VertraulichkeitBereich: Interne Datenoffenlegung

Angreifer können Daten von internen Diensten, Cloud-Metadaten und lokalen Dateien lesen.
IntegritätBereich: Manipulation interner Dienste

SSRF kann verwendet werden, um Daten auf internen Diensten zu modifizieren oder Aktionen auszulösen.
ZugriffskontrolleBereich: Firewall-Umgehung

Angreifer umgehen Netzwerk-Sicherheitskontrollen, indem sie den Server als Proxy verwenden.

Beispielcode + Lösungscode

Anfälliger Code

# ANFÄLLIG: Abrufen einer vom Benutzer bereitgestellten URL ohne Validierung
import requests
from flask import Flask, request

@app.route('/fetch')
def fetch_url():
    url = request.args.get('url')
    # Angreifer gibt an: url=http://169.254.169.254/latest/meta-data/
    # Server ruft AWS-Metadaten mit Anmeldedaten ab!
    response = requests.get(url)
    return response.text

# ANFÄLLIG: Webhook ohne URL-Validierung
@app.route('/webhook', methods=['POST'])
def create_webhook():
    webhook_url = request.json['callback_url']
    # Speichern und später diese URL aufrufen - könnte interner Dienst sein!
    save_webhook(webhook_url)
    return 'Webhook registriert'

# ANFÄLLIG: Bild-Proxy ohne Validierung
@app.route('/proxy/image')
def proxy_image():
    image_url = request.args.get('url')
    response = requests.get(image_url)
    return response.content, 200, {'Content-Type': 'image/png'}
// ANFÄLLIG: URL-Abruf ohne Validierung
@RestController
public class UrlFetcherController {

    @GetMapping("/fetch")
    public String fetchUrl(@RequestParam String url) throws Exception {
        // Angreifer: url=file:///etc/passwd
        URL urlObj = new URL(url);
        HttpURLConnection conn = (HttpURLConnection) urlObj.openConnection();
        return new String(conn.getInputStream().readAllBytes());
    }
}

// ANFÄLLIG: PDF-Generator mit externen Ressourcen
@PostMapping("/generate-pdf")
public byte[] generatePdf(@RequestBody PdfRequest request) {
    // Angreifer fügt ein: <img src="http://internal-api/admin/users">
    // PDF-Engine ruft interne URL ab!
    return pdfGenerator.generate(request.getHtml());
}

Korrigierter Code

# SICHER: URL-Validierung mit Allowlist und Blocklist
import requests
import ipaddress
from urllib.parse import urlparse
import socket

ALLOWED_SCHEMES = {'http', 'https'}
ALLOWED_DOMAINS = {'api.example.com', 'cdn.example.com'}
BLOCKED_IP_RANGES = [
    ipaddress.ip_network('10.0.0.0/8'),
    ipaddress.ip_network('172.16.0.0/12'),
    ipaddress.ip_network('192.168.0.0/16'),
    ipaddress.ip_network('127.0.0.0/8'),
    ipaddress.ip_network('169.254.0.0/16'),  # AWS-Metadaten
    ipaddress.ip_network('0.0.0.0/8'),
]

def is_safe_url(url):
    """Validiert, ob URL sicher abgerufen werden kann."""
    try:
        parsed = urlparse(url)

        # Schema prüfen
        if parsed.scheme not in ALLOWED_SCHEMES:
            return False, "Ungültiges Schema"

        # Gegen Allowlist prüfen (wenn Allowlist-Ansatz verwendet wird)
        if ALLOWED_DOMAINS and parsed.hostname not in ALLOWED_DOMAINS:
            return False, "Domain nicht erlaubt"

        # Hostname zu IP auflösen und gegen Blocklist prüfen
        try:
            ip = ipaddress.ip_address(socket.gethostbyname(parsed.hostname))
        except (socket.gaierror, ValueError):
            return False, "Hostname kann nicht aufgelöst werden"

        for blocked_range in BLOCKED_IP_RANGES:
            if ip in blocked_range:
                return False, "IP-Adresse blockiert"

        return True, None

    except Exception as e:
        return False, str(e)

@app.route('/fetch')
def fetch_url_safe():
    url = request.args.get('url')

    is_safe, error = is_safe_url(url)
    if not is_safe:
        return f'Ungültige URL: {error}', 400

    # Timeout verwenden und Weiterleitungen deaktivieren, um SSRF via Redirect zu verhindern
    response = requests.get(url, timeout=5, allow_redirects=False)

    # Bei Weiterleitung erneut validieren
    if response.is_redirect:
        return 'Weiterleitungen nicht erlaubt', 400

    return response.text
// SICHER: URL-Validierung mit IP-Blocklist
@RestController
public class SecureUrlFetcherController {

    private static final Set<String> ALLOWED_SCHEMES = Set.of("http", "https");
    private static final List<String> BLOCKED_PREFIXES = List.of(
        "10.", "172.16.", "172.17.", "172.18.", "172.19.",
        "172.20.", "172.21.", "172.22.", "172.23.", "172.24.",
        "172.25.", "172.26.", "172.27.", "172.28.", "172.29.",
        "172.30.", "172.31.", "192.168.", "127.", "169.254.", "0."
    );

    @GetMapping("/fetch")
    public String fetchUrlSafe(@RequestParam String url) throws Exception {
        URL urlObj = new URL(url);

        // Schema validieren
        if (!ALLOWED_SCHEMES.contains(urlObj.getProtocol().toLowerCase())) {
            throw new SecurityException("Ungültiges URL-Schema");
        }

        // IP auflösen und validieren
        InetAddress address = InetAddress.getByName(urlObj.getHost());
        String ip = address.getHostAddress();

        for (String prefix : BLOCKED_PREFIXES) {
            if (ip.startsWith(prefix)) {
                throw new SecurityException("Blockierte IP-Adresse");
            }
        }

        // Zusätzliche Prüfung auf Loopback
        if (address.isLoopbackAddress() || address.isLinkLocalAddress()) {
            throw new SecurityException("Lokale Adressen nicht erlaubt");
        }

        // Mit Timeout abrufen
        HttpURLConnection conn = (HttpURLConnection) urlObj.openConnection();
        conn.setConnectTimeout(5000);
        conn.setReadTimeout(5000);
        conn.setInstanceFollowRedirects(false);

        return new String(conn.getInputStream().readAllBytes(), StandardCharsets.UTF_8);
    }
}

Ausgenutzt in der Praxis

Capital One Datenleck (Capital One, 2019)

Angreifer nutzten SSRF über eine fehlkonfigurierte WAF aus, um auf AWS-Metadaten-Dienste unter 169.254.169.254 zuzugreifen und IAM-Anmeldedaten abzurufen, die Zugang zu S3-Buckets mit persönlichen Informationen von über 100 Millionen Kunden ermöglichten.

Apache HTTP Server NTLM-Hash-Erfassung (Apache, 2024)

CVE-2024-43394 im Apache HTTP Server 2.4.0-2.4.63 unter Windows ermöglicht SSRF, das SMB-Verbindungen zu angreifergesteuerten Hosts auslöst und die Erfassung von NTLM-Authentifizierungs-Hashes zum Cracken oder für Relay-Angriffe ermöglicht.

LiteSpeed Cache SSRF (LiteSpeed, 2025)

CVE-2025-47437 in LiteSpeed Cache bis 7.0.1 ermöglicht authentifizierten Benutzern mit niedrigen Privilegien, serverseitige Anfragen an interne oder externe Ressourcen ohne Benutzerinteraktion zu stellen.


Tools zum Testen/Ausnutzen


CVE-Beispiele


Referenzen

  1. MITRE. "CWE-918: Server-Side Request Forgery (SSRF)." https://cwe.mitre.org/data/definitions/918.html

  2. OWASP. "Server-Side Request Forgery Prevention Cheat Sheet." https://cheatsheetseries.owasp.org/cheatsheets/Server_Side_Request_Forgery_Prevention_Cheat_Sheet.html