Wie externe Entities in XML missbraucht werden und wie man sich schützt
XML-Parser mit aktivierter externer Entity-Verarbeitung lassen sich für Dateizugriff oder SSRF missbrauchen. Wir zeigen, wie XXE funktioniert, warum viele moderne XML-Bibliotheken das standardmäßig deaktiviert haben, und wie DOMDocument in PHP explizit abgesichert wird.
Inhaltsverzeichnis
- 1. Was ist ein XXE-Angriff?
- 2. Wie ein XXE-Angriff im Detail funktioniert
- 3. Warum viele moderne Bibliotheken bereits schützen
- 4. Typische Einfallstore für XXE
- 5. Folgen eines erfolgreichen XXE-Angriffs
- 6. Explizite Absicherung in PHP
- 7. Sonderfall SVG-Uploads
- 8. Testing und Code-Review für XXE
- 9. Best Practices und Checkliste
- 10. Zusammenfassung
- 11. FAQ
1. Was ist ein XXE-Angriff?
XML erlaubt die Definition eigener Entities innerhalb eines Dokuments, ähnlich wie Variablen. Externe Entities gehen einen Schritt weiter und können auf eine externe Ressource verweisen, etwa eine lokale Datei oder eine URL. Verarbeitet ein XML-Parser diese externen Entities, ohne dass der Entwickler das bewusst so konfiguriert hat, entsteht die Grundlage für einen XXE-Angriff. Die Schwachstelle ist seit vielen Jahren bekannt, taucht in Sicherheitsaudits aber immer wieder auf, weil XML-Verarbeitung oft in älteren, seltener geprüften Codeteilen steckt.
Ein Angreifer definiert dabei im XML-Dokument eine externe Entity, die auf eine sensible lokale Datei wie /etc/passwd oder eine interne Konfigurationsdatei verweist, und referenziert diese Entity anschließend an einer Stelle, deren Inhalt in der Antwort der Anwendung sichtbar wird.
2. Wie ein XXE-Angriff im Detail funktioniert
Ein typisches bösartiges XML-Dokument definiert im DOCTYPE-Bereich eine externe Entity mit dem Schlüsselwort SYSTEM, gefolgt von einem Pfad oder einer URL. Wird diese Entity anschließend in einem Textknoten referenziert, ersetzt ein anfälliger Parser die Referenz durch den Inhalt der referenzierten Ressource und baut ihn direkt in den geparsten Dokumentbaum ein.
Zusätzlich zur libxml-Konfiguration lehnt die abgesicherte Variante im folgenden Beispiel jedes Dokument mit einem DOCTYPE grundsätzlich ab, da eine Rechnungs- oder Bestell-XML fachlich niemals eine Doctype-Definition benötigt. Diese Kombination aus Konfiguration und fachlicher Validierung reduziert die Angriffsfläche auf ein Minimum, selbst falls sich das Verhalten einer libxml-Version in Zukunft ändern sollte.
<?php
declare(strict_types=1);
namespace App\Service;
final class InvoiceXmlImporter
{
// Verwundbar: Externe Entities und Netzwerkzugriff sind nicht deaktiviert
public function importVulnerable(string $xmlContent): \DOMDocument
{
$document = new \DOMDocument();
$document->loadXML($xmlContent);
return $document;
}
// Abgesichert: Externe Entities, DTDs und Netzwerkzugriff explizit sperren
public function importSecured(string $xmlContent): \DOMDocument
{
$document = new \DOMDocument();
// Seit PHP 8 sind externe Entities in libxml standardmäßig deaktiviert,
// die explizite Konfiguration bleibt trotzdem als defense in depth sinnvoll.
$previousSetting = libxml_use_internal_errors(true);
$success = $document->loadXML($xmlContent, LIBXML_NONET);
if ($success === false || $document->doctype !== null) {
libxml_use_internal_errors($previousSetting);
throw new \InvalidArgumentException('XML document with DOCTYPE is not allowed.');
}
libxml_use_internal_errors($previousSetting);
return $document;
}
}
3. Warum viele moderne Bibliotheken bereits schützen
Seit PHP 8.0 verarbeitet die zugrunde liegende libxml-Bibliothek externe Entities standardmäßig nicht mehr automatisch, nachdem in älteren PHP-Versionen die Funktion libxml_disable_entity_loader explizit aufgerufen werden musste. Diese Funktion ist inzwischen als deprecated markiert, weil ihr Zweck durch das neue Standardverhalten weitgehend übernommen wurde. Projekte, die noch auf PHP 7 oder älter laufen, sollten diesen Aufruf trotzdem konsequent beibehalten, da sie sonst vollständig auf den alten, unsicheren Standardzustand angewiesen sind.
Aehnliche Entwicklungen gab es in vielen anderen Sprachökosystemen: Moderne XML-Bibliotheken liefern XXE-sichere Defaults aus, weil die Schwachstelle über Jahre so häufig auftrat, dass ein Opt-in statt eines Opt-out als sinnvoller galt. Trotzdem bleibt Vorsicht geboten, weil ältere Bibliotheksversionen, Legacy-Code oder alternative XML-Parser wie SimpleXML unter bestimmten Konfigurationen weiterhin anfällig sein können.
4. Typische Einfallstore für XXE
XXE tritt überall dort auf, wo eine Anwendung XML-Daten von außen entgegennimmt und parst: Datei-Uploads im XML-, SVG- oder DOCX-Format, SOAP-Schnittstellen, RSS- und Atom-Feed-Importe sowie Konfigurationsimporte, die im XML-Format vorliegen. Besonders SVG-Dateien werden oft übersehen, obwohl sie technisch vollwertige XML-Dokumente mit DOCTYPE-Unterstützung sind. Auch Office-Formate wie DOCX oder XLSX bestehen intern aus mehreren XML-Dateien in einem ZIP-Container und sind deshalb potenziell ebenso betroffen.
Auch scheinbar interne Schnittstellen sind betroffen, etwa ein XML-basierter Import von Produktdaten oder Rechnungen aus einem ERP-System, wenn die hochgeladene Datei nicht ausschließlich von vertrauenswürdigen internen Systemen stammt, sondern etwa von externen Lieferanten hochgeladen werden kann. Gerade B2B-Schnittstellen mit vielen angebundenen Partnern sind hier besonders exponiert, da jeder einzelne Partner potenziell zum Einfallstor werden kann.
5. Folgen eines erfolgreichen XXE-Angriffs
Ein erfolgreicher XXE-Angriff erlaubt häufig das Auslesen beliebiger lokaler Dateien, auf die der PHP-Prozess Lesezugriff hat, inklusive Konfigurationsdateien mit Datenbank-Zugangsdaten oder privaten Schlüsseln. Ist zusätzlich Netzwerkzugriff durch den Parser möglich, lässt sich XXE auch für SSRF-Angriffe gegen interne Systeme nutzen, etwa um Cloud-Metadaten-Endpunkte oder interne Admin-Oberflächen anzusprechen, die von außen sonst nicht erreichbar wären.
In besonders ungünstigen Konfigurationen sind sogar sogenannte Billion-Laughs-Angriffe möglich, bei denen verschachtelte Entity-Definitionen exponentiell expandieren und den Server durch Speicher- oder CPU-Erschöpfung in einen Denial-of-Service-Zustand versetzen. Solche Angriffe benötigen nicht einmal externen Netzwerkzugriff, da die Entities vollständig innerhalb des Dokuments definiert werden können, was sie besonders schwer allein durch Netzwerkfilterung zu verhindern macht.
6. Explizite Absicherung in PHP
Auch wenn PHP 8 externe Entities standardmäßig deaktiviert, empfiehlt sich weiterhin die explizite Verwendung von LIBXML_NONET, um jeglichen Netzwerkzugriff durch den Parser zu unterbinden, sowie eine bewusste Ablehnung von Dokumenten mit DOCTYPE-Definition für alle Formate, die fachlich keine Doctype benötigen. Diese defense-in-depth-Strategie schützt auch dann, wenn eine Anwendung versehentlich auf einer älteren PHP-Version oder in einer Umgebung mit abweichender libxml-Konfiguration betrieben wird.
Für SimpleXML gelten dieselben zugrunde liegenden libxml-Einstellungen wie für DOMDocument, da beide auf derselben C-Bibliothek aufbauen. Wird XML über simplexml_load_string verarbeitet, sollten dieselben Flags wie LIBXML_NONET gesetzt und die DOCTYPE-Prüfung ebenso konsequent durchgeführt werden. Dasselbe gilt für XMLReader und die SOAP-Erweiterung, die intern ebenfalls auf libxml aufsetzen und deshalb dieselben Absicherungsprinzipien benötigen.
7. Sonderfall SVG-Uploads
SVG-Dateien werden in Upload-Formularen oft wie normale Bilddateien behandelt, sind technisch aber vollwertiges XML und können DOCTYPE-Definitionen mit externen Entities enthalten. Wird eine hochgeladene SVG-Datei serverseitig geparst, etwa für eine Vorschau oder Größenanpassung, muss dieselbe XXE-Absicherung greifen wie bei jedem anderen XML-Import.
Eine zusätzliche, robuste Maßnahme ist, hochgeladene SVG-Dateien vor der Auslieferung durch eine dedizierte Sanitizer-Bibliothek zu bereinigen, die DOCTYPE-Definitionen, Skript-Tags und externe Referenzen konsequent entfernt, statt sich ausschließlich auf die Parser-Konfiguration zu verlassen. Diese doppelte Absicherung lohnt sich besonders bei Uploads, die später direkt im Browser eines anderen Nutzers angezeigt werden, da dort zusätzlich Cross-Site-Scripting-Risiken durch eingebettete Skripte drohen.
8. Testing und Code-Review für XXE
Ein gezielter Test schickt an jeden XML-verarbeitenden Endpunkt ein Dokument mit einer externen Entity, die auf eine bekannte, harmlose lokale Datei verweist, etwa eine PHP-eigene Konfigurationsdatei, und prüft, ob deren Inhalt in der Antwort auftaucht. Zusätzlich sollte ein Dokument mit Verweis auf eine interne Test-URL genutzt werden, um SSRF über XXE auszuschließen. Ein dritter Testfall mit einer moderat verschachtelten Entity-Definition deckt ausserdem ab, ob der Parser gegen einfache Billion-Laughs-Varianten geschützt ist.
Im Code-Review lohnt sich eine gezielte Suche nach loadXML-, simplexml_load_string- und SOAP-Aufrufen, um sicherzustellen, dass jede dieser Stellen entweder auf einer aktuellen PHP-Version mit sicherem Standardverhalten läuft oder explizit mit LIBXML_NONET und einer DOCTYPE-Ablehnung abgesichert ist.
9. Best Practices und Checkliste
Jede Stelle, die XML aus einer nicht vollständig vertrauenswürdigen Quelle parst, sollte explizit LIBXML_NONET setzen, Dokumente mit DOCTYPE grundsätzlich ablehnen, sofern fachlich keine Doctype benötigt wird, und auf einer aktuellen PHP-Version mit sicherem libxml-Standardverhalten laufen.
Ergänzend gehören eine spezielle Behandlung von SVG-Uploads, ein automatisierter XXE-Test pro XML-Endpunkt sowie ein regelmäßiges Update der zugrunde liegenden libxml-Version zu einer robusten Absicherung gegen XXE.
| Einfallstor | Beispiel | Risiko | Gegenmaßnahme |
|---|---|---|---|
| XML-Datei-Upload | Rechnungsimport per XML | Auslesen lokaler Dateien | DOCTYPE ablehnen, LIBXML_NONET |
| SVG-Upload | Profilbild im SVG-Format | XXE über Bild-Endpunkt | SVG-Sanitizer plus Parser-Absicherung |
| SOAP-Schnittstelle | Externe Partneranbindung | SSRF über XML-Payload | Netzwerkzugriff im Parser deaktivieren |
| Feed-Import | RSS/Atom-Feed einlesen | Denial of Service via Billion Laughs | Entity-Expansion begrenzen, DOCTYPE sperren |
Mironsoft
Security-Audits, OWASP-konforme Härtung und sichere Architektur
Anwendungen, die einem echten Angriffsversuch tatsächlich standhalten?
Wir prüfen bestehende Anwendungen auf klassische OWASP-Schwachstellen, unsichere Authentifizierung und fehlende Input-Validierung und bauen daraus eine Architektur, die Angriffsflächen strukturell reduziert statt nur einzelne Symptome zu flicken.
Security-Audit
OWASP Top 10, Auth-Flows und Input-Validierung systematisch auf Schwachstellen prüfen.
Sichere Architektur
Rate-Limiting, Verschlüsselung und Zugriffskontrollen von Grund auf richtig aufbauen.
Incident-Vorbereitung
Logging, Monitoring und Reaktionsprozesse für den Ernstfall etablieren.
10. Zusammenfassung
XXE
Ursache
Parser verarbeitet externe Entities in XML-Dokumenten.
Erkennung
Test mit Entity-Referenz auf bekannte lokale Datei.
Fix
LIBXML_NONET, DOCTYPE-Ablehnung, aktuelle PHP-Version.
Prävention
Code-Review auf loadXML-Aufrufe, SVG-Sanitizing.