libxml_disable_entity_loader()
Erklärung der PHP-Funktion libxml_disable_entity_loader(): Zweck, XXE-Schutz, Entfernung in PHP 8.1 und sichere Alternativen für modernes PHP.
Die PHP-Funktion libxml_disable_entity_loader() wurde verwendet, um das Laden externer Entitäten für alle XML-Dokumente, die von der libxml-Erweiterung geparst werden, ein- oder auszuschalten. Diese Seite erklärt, was die Funktion tat, welchen XML External Entity (XXE)-Angriff sie schützte, warum sie entfernt wurde und wie man heute sicheren XML-Parsing-Code in modernem PHP schreibt.
Wichtig: libxml_disable_entity_loader() wurde in PHP 8.0 als veraltet markiert und in PHP 8.1 entfernt. Wenn Sie PHP 8.1 oder neuer verwenden, löst ein Aufruf einen schwerwiegenden Fehler aus. Verwenden Sie stattdessen die sicheren Alternativen unten.
Was libxml_disable_entity_loader() tat
libxml_disable_entity_loader() war ein eingebautes PHP-Hilfsmittel, das ein globales Flag innerhalb von libxml umschaltete — der C-Bibliothek, die PHPs DOMDocument und SimpleXML antreibt. Wenn das Flag gesetzt war, verweigerte libxml die Auflösung von externen Entitäten: Referenzen in einem XML-Dokument, die auf eine externe Ressource zeigen, wie eine lokale Datei (file:///etc/passwd) oder eine Remote-URL.
Das Blockieren dieser Auflösung war die Standardmethode zum Schutz vor XML External Entity (XXE)-Angriffen. Bei einem XXE-Angriff übermittelt der Angreifer eine XML-Nutzlast, deren DOCTYPE eine Entität deklariert, die auf eine sensible Ressource zeigt:
<?xml version="1.0"?>
<!DOCTYPE data [
<!ENTITY xxe SYSTEM "file:///etc/passwd">
]>
<data>&xxe;</data>Wenn der Parser &xxe; auflöst, landen die Inhalte von /etc/passwd im geparsten Dokument — das die Anwendung dann ausgeben, protokollieren oder speichern könnte. Derselbe Trick ermöglicht Server-Side Request Forgery (SSRF, indem die Entität auf eine interne URL zeigt) und Denial of Service (die „Billion Laughs" Entitätserweiterungs-Bombe).
Syntax
libxml_disable_entity_loader(bool $disable = true): boolParameter
| Parameter | Typ | Beschreibung |
|---|---|---|
$disable | bool | true deaktiviert das Laden externer Entitäten; false aktiviert es wieder. Standardmäßig true. |
Rückgabewert
Gibt den vorherigen Wert des Flags als boolean zurück, sodass Sie den früheren Zustand nach einem einzelnen Parse-Vorgang wiederherstellen konnten.
Bisherige Verwendung
In PHP 7.x und früher sah das Absichern eines Parse-Vorgangs so aus. Der Aufruf ist in function_exists() eingebettet, damit derselbe Code auch auf PHP 8.1+ weiter funktioniert, wo die Funktion nicht mehr existiert:
<?php
// Disable external entities (deprecated in PHP 8.0, removed in 8.1).
if (function_exists('libxml_disable_entity_loader')) {
libxml_disable_entity_loader(true);
}
// Load an XML file into a DOMDocument object.
$doc = new DOMDocument();
if (!$doc->load('example.xml')) {
die('Failed to load XML file.');
}
?>Ein verbreitetes, sichereres Muster war es, den vorherigen Wert zu erfassen und wiederherzustellen, damit das Deaktivieren von Entitäten nicht in andere Parse-Vorgänge innerhalb derselben Anfrage hineinreichte:
<?php
$previous = libxml_disable_entity_loader(true);
$doc = new DOMDocument();
$doc->loadXML($untrustedXml);
// Restore the global flag for the rest of the request.
libxml_disable_entity_loader($previous);
?>Sichere Alternativen in modernem PHP
Zwei Dinge haben sich in modernem PHP geändert, die die Funktion überflüssig machten:
- libxml 2.9+ deaktiviert das Laden externer Entitäten standardmäßig. Seit dieser Version (die seit Jahren mit PHP ausgeliefert wird), werden externe DTD-Entitäten nicht aufgelöst, es sei denn, Sie fordern das explizit an. Deshalb wurde die Funktion überflüssig und wurde entfernt.
LIBXML_NONETbietet Kontrolle pro Aufruf. Anstatt ein globales Flag umzuschalten, übergeben Sie ein Flag an den spezifischen Ladeaufruf, das den Netzwerkzugriff beim Parsen blockiert:
<?php
$doc = new DOMDocument();
// Parse without ever touching the network — no SSRF, no remote entities.
$doc->load('example.xml', LIBXML_NONET);
?>Wenn Sie DTDs unterstützen müssen, aber dennoch absichern wollen, vermeiden Sie LIBXML_DTDLOAD / LIBXML_NOENT bei nicht vertrauenswürdigen Eingaben, da diese Flags genau das Verhalten wieder aktivieren, auf das XXE angewiesen ist. Der sicherste Standard besteht darin, sie einfach nicht zu übergeben:
<?php
$doc = new DOMDocument();
// Default flags (0): no entity substitution, no DTD loading from untrusted XML.
$doc->loadXML($untrustedXml);
// SimpleXML follows the same secure default.
$xml = simplexml_load_string($untrustedXml);
?>Um Parse-Probleme zu untersuchen, anstatt rohe Warnungen auszugeben, kombinieren Sie den Ladevorgang mit libxml_use_internal_errors() und lesen Sie diese über libxml_get_errors() aus.
Wann würde ich das verwenden?
libxml_disable_entity_loader() begegnet Ihnen nur beim Lesen oder Warten von Legacy-PHP-7-Code. Für jeden Code, den Sie heute schreiben:
- Auf PHP 8.1+ ist nichts Besonderes für Entitäten erforderlich — der sichere Standard gilt bereits. Fügen Sie
LIBXML_NONEThinzu, wenn Sie auch den Netzwerkzugriff blockieren möchten. - Alten Code migrieren? Ersetzen Sie
libxml_disable_entity_loader(true)durch dasLIBXML_NONET-Flag bei jedem Ladeaufruf, oder wickeln Sie den Aufruf infunction_exists()ein, damit er auf neuen Laufzeitumgebungen keine Funktion ausführt.
Fazit
libxml_disable_entity_loader() war einst die bevorzugte Verteidigung gegen XXE-Angriffe, basierte jedoch auf einem fragilen globalen Flag und wurde seit PHP 8.1 entfernt. Modernes PHP ist dank libxml 2.9+ standardmäßig sicher, und LIBXML_NONET gibt Ihnen explizite Kontrolle pro Parse-Vorgang. Mehr zum PHP-XML-Stack finden Sie in der Übersicht der libxml-Erweiterung und unter Arbeiten mit dem XML-DOM.