Kurz gesagt: SSRF in PHP verhindern Sie, indem Ihre Anwendung nur Adressen abruft, die auf einer festen Erlaubnisliste stehen, ausschließlich per HTTPS, ohne Weiterleitungen zu folgen. Die aufgelöste IP-Adresse wird gegen private und reservierte Bereiche geprüft und dann für die Verbindung festgehalten. Eine Firewall für ausgehenden Verkehr sorgt dafür, dass interne Systeme auch bei einem Fehler im Code unerreichbar bleiben.
Wenn der eigene Server für Fremde Anfragen stellt
Link-Vorschauen in einem Chat, Import eines Produktbilds per URL, Webhooks an Partnersysteme, ein Feed-Reader im CMS: Viele PHP-Anwendungen rufen Adressen ab, die ein Nutzer angegeben hat. Das ist eine nützliche Funktion und zugleich eine Tür nach innen.
Bei Server-Side Request Forgery, kurz SSRF, bringt ein Angreifer die Anwendung dazu, eine Anfrage an ein Ziel seiner Wahl zu senden. Der Clou: Die Anfrage kommt vom Server selbst. Sie erreicht damit Systeme, die von außen gesperrt sind, etwa Datenbanken, Verwaltungsoberflächen im internen Netz, Dienste, die nur auf localhost lauschen, oder die Metadaten-Dienste von Cloud-Anbietern.
In den OWASP Top 10 von 2021 war SSRF eine eigene Kategorie. In PHP-Projekten taucht die Lücke häufig dort auf, wo jemand schnell eine „Bild per URL hinzufügen“-Funktion gebaut hat.
SSRF in PHP: Welche Funktionen Adressen abrufen
Nicht nur cURL ruft Adressen ab. Folgende Stellen sollten Sie im Blick haben:
| Funktion oder Bereich | Warum relevant |
|---|---|
cURL (curl_exec()) |
häufigster Weg, viele Protokolle möglich |
file_get_contents(), fopen(), copy() mit URL |
nutzen URL-Wrapper, wenn allow_url_fopen aktiv ist |
getimagesize() und Bildbibliotheken |
können entfernte Dateien laden |
| XML-Verarbeitung, SOAP-Clients | laden unter Umständen externe Ressourcen |
| HTTP-Bibliotheken wie Guzzle | bauen auf cURL oder Streams auf, gleiche Regeln |
Wenn Ihre Anwendung keine entfernten Dateien über Dateifunktionen öffnen muss, schalten Sie allow_url_fopen serverseitig ab. Ein verwandtes Thema, das Einbinden von Dateien über Pfade aus der Anfrage, behandelt der Ratgeber Local und Remote File Inclusion verhindern.
Die Verteidigung in fünf Schritten
OWASP empfiehlt eine Kombination aus Maßnahmen, die einzeln jeweils umgangen werden könnten, zusammen aber tragen:
- Erlaubnisliste statt freier URL: Am besten wählt der Nutzer nur aus bekannten Zielen, oder er gibt lediglich einen Bezeichner an, und die Anwendung baut die Adresse selbst.
- Nur HTTPS erlauben: Andere Protokolle wie
file,gopheroderftpin cURL ausschließen, auch für Weiterleitungen. - Keinen Weiterleitungen folgen: Eine erlaubte Adresse kann sonst auf ein internes Ziel umleiten.
- Aufgelöste Adresse prüfen und festhalten: Den Hostnamen auflösen, die IP gegen private, Loopback- und Link-Local-Bereiche prüfen und genau diese IP für die Verbindung verwenden. Sonst kann eine zweite DNS-Auflösung ein anderes Ziel liefern.
- Netzwerk begrenzen: Der Webserver darf nach außen nur die Ziele erreichen, die er braucht.
Ein sicheres Muster mit cURL
Das folgende Beispiel setzt die Schritte 1 bis 4 für IPv4 um. Hostnamen und Ablauf sind Beispiele; für IPv6 gelten dieselben Prüfungen.
<?php
declare(strict_types=1);
function ladeVonPartner(string $url): string
{
$teile = parse_url($url);
if (!is_array($teile) || ($teile['scheme'] ?? '') !== 'https'
|| isset($teile['user']) || isset($teile['pass']) || isset($teile['port'])) {
throw new InvalidArgumentException('Adresse nicht erlaubt.');
}
$host = strtolower($teile['host'] ?? '');
$erlaubt = ['api.partner.example', 'bilder.partner.example'];
if (!in_array($host, $erlaubt, true)) {
throw new InvalidArgumentException('Ziel nicht erlaubt.');
}
$ip = gethostbyname($host);
$oeffentlich = filter_var($ip, FILTER_VALIDATE_IP,
FILTER_FLAG_IPV4 | FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE);
if ($oeffentlich === false) {
throw new RuntimeException('Ziel löst auf eine nicht erlaubte Adresse auf.');
}
$ch = curl_init($url);
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_FOLLOWLOCATION => false,
CURLOPT_PROTOCOLS => CURLPROTO_HTTPS,
CURLOPT_REDIR_PROTOCOLS => CURLPROTO_HTTPS,
CURLOPT_RESOLVE => [$host . ':443:' . $ip],
CURLOPT_CONNECTTIMEOUT => 3,
CURLOPT_TIMEOUT => 10,
]);
$antwort = curl_exec($ch);
if ($antwort === false) {
throw new RuntimeException('Abruf fehlgeschlagen.');
}
return $antwort;
}
Einige Details sind wichtig. gethostbyname() gibt bei einem Fehler den Hostnamen zurück; die anschließende IP-Prüfung fängt das ab. Die Flags FILTER_FLAG_NO_PRIV_RANGE und FILTER_FLAG_NO_RES_RANGE schließen laut PHP-Handbuch unter anderem die Bereiche 10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16, 127.0.0.0/8 und 169.254.0.0/16 aus. Seit PHP 8.2 gibt es zusätzlich FILTER_FLAG_GLOBAL_RANGE, das nur global gültige Adressen zulässt. CURLOPT_RESOLVE sorgt dafür, dass cURL genau die geprüfte Adresse nutzt, während Hostname und Zertifikatsprüfung erhalten bleiben.
Zwei weitere Punkte begrenzen, was ein Angreifer aus einer SSRF-Lücke lernt. Geben Sie Antworten und Fehlermeldungen des abgerufenen Ziels nicht ungefiltert an den Nutzer zurück: Schon die Unterscheidung zwischen „Verbindung abgelehnt“ und „Zeitüberschreitung“ verrät, welche internen Dienste existieren. Und begrenzen Sie Laufzeit und Größe der Antwort, damit die Funktion nicht zur Überlastung des eigenen Servers taugt. Webhooks an Adressen, die Kunden selbst eintragen, versenden Sie am besten aus einer Warteschlange und nicht während der laufenden Anfrage.
Muss Ihre Anwendung wirklich beliebige Adressen abrufen, etwa für Link-Vorschauen, lagern Sie diese Funktion in einen getrennten Dienst ohne Zugang zum internen Netz aus. Eine Erlaubnisliste ist dann nicht möglich, die Netztrennung umso wichtiger.
Die Netzwerkebene als Sicherheitsnetz
Code-Prüfungen können Lücken haben, etwa wenn zwei Bibliotheken eine URL unterschiedlich zerlegen. OWASP rät, solche Unstimmigkeiten als Ablehnung zu behandeln und zusätzlich auf Netzwerkebene zu begrenzen. Ein Webserver braucht nach außen meist nur wenige Ziele: Paketquellen, Zahlungs- und Versanddienstleister, Mailrelay, bestimmte Schnittstellen.
Eine Firewall für ausgehenden Verkehr hilft doppelt. Sie stoppt SSRF-Anfragen ins interne Netz, und sie erschwert nach einem Einbruch, etwa über eine ungepatchte PHP-Version, das Nachladen weiterer Werkzeuge. Wie Sie die Regeln aufbauen, beschreibt Firewall für Webserver: Nur nötige Ports öffnen. Welche Verbindungen ein Server tatsächlich aufbaut, zeigt Ausgehende Verbindungen eines Servers prüfen.
In Cloud-Umgebungen gehört die gehärtete Variante des Metadaten-Dienstes dazu. OWASP nennt für AWS den Umstieg auf IMDSv2 und das Abschalten von IMDSv1.
SSRF im Bestandscode aufspüren
Ein schneller Einstieg ist die Suche nach Stellen, an denen Abruffunktionen Werte aus der Anfrage erhalten:
grep -rnE "(curl_init|file_get_contents|fopen|getimagesize|copy)\s*\(" src/ --include="*.php" | grep -E '\$_(GET|POST|REQUEST)|\$url'
grep -rn "CURLOPT_FOLLOWLOCATION" src/ --include="*.php"
Treffer sind Prüfaufträge. Besonders gründlich sollten Sie Funktionen ansehen, die Admins nutzen: Importe, Webhook-Einstellungen, Update-Prüfungen von Plugins.
Leicht übersehen werden PDF-Generatoren, die HTML mit eingebundenen Bildern oder Stylesheets in Dokumente umwandeln. Stammt ein Teil dieses HTML aus Nutzereingaben, etwa bei Rechnungen mit frei wählbarem Logo, ruft der Generator unter Umständen Adressen ab, die der Nutzer bestimmt. Prüfen Sie dort die Einstellungen für das Laden entfernter Ressourcen und schalten Sie es ab, wenn es nicht gebraucht wird.
Wie hilft PHP SOS konkret?
- Wir finden alle Stellen, an denen Ihre Anwendung Adressen abruft, auch in Plugins und Bibliotheken.
- Wir bauen eine zentrale Abruffunktion mit Erlaubnisliste, Protokollbeschränkung und IP-Prüfung.
- Wir legen Regeln für ausgehenden Verkehr fest und schützen Metadaten-Dienste in Cloud-Umgebungen.
- Wir prüfen die Umsetzung von außen und dokumentieren erlaubte Ziele.
Eine unabhängige Prüfung Ihrer Anwendung beschreibt Sicherheitsaudit und Penetrationstest.
Häufige Fragen
Welche PHP-Funktionen können für SSRF missbraucht werden?
Alle, die eine Adresse aus Benutzereingaben abrufen: cURL, file_get_contents und fopen mit URL-Wrappern, Bild- und XML-Funktionen, die entfernte Dateien laden, sowie Bibliotheken für Webhooks, Feeds oder Link-Vorschauen.
Reicht es, interne IP-Adressen zu sperren?
Allein nicht. OWASP bezeichnet Sperrlisten als umgehungsanfällig und empfiehlt Erlaubnislisten. Zusätzlich muss die Anwendung genau die Adresse verwenden, die sie geprüft hat, und darf keinen Weiterleitungen folgen.
Warum ist SSRF in der Cloud besonders kritisch?
Cloud-Anbieter stellen Instanzen interne Metadaten-Dienste bereit, über die teilweise Zugangsdaten abrufbar sind. Kann eine Anwendung dorthin Anfragen schicken, kann ein Angreifer diese Daten über sie erreichen. Die Anbieter bieten gehärtete Varianten dieser Dienste an, die aktiviert sein sollten.
Was bringt eine Firewall für ausgehenden Verkehr?
Sie begrenzt, welche Ziele der Server überhaupt erreichen kann. Selbst wenn eine Prüfung im Code versagt, bleiben interne Systeme dann unerreichbar. Außerdem erschwert sie nach einem Einbruch das Nachladen von Schadcode und den Abfluss von Daten.