Start · Sprachen · PHP · Referenz · libxml_set_external_entity_loader

libxml_set_external_entity_loader

Funktion

Setzt eine benutzerdefinierte Callback-Funktion, die beim Auflösen externer XML-Entities aufgerufen wird, und ersetzt damit den Standard-Loader von libxml.

seit PHP 5.4.0 Kategorie: xml

Signatur

libxml_set_external_entity_loader(?callable $resolver_function): bool

Beschreibung

libxml_set_external_entity_loader() ermöglicht es, den internen Mechanismus von libxml zum Laden externer Entities durch eine eigene PHP-Funktion zu ersetzen. Immer wenn libxml eine externe Entity auflösen muss (z. B. eine DTD oder eine externe XML-Datei), wird statt des Standard-Loaders die registrierte Callback-Funktion aufgerufen.

Die Callback-Funktion erhält drei Parameter: $public (den öffentlichen Bezeichner der Entity, oft null), $system (den System-Bezeichner, also die URL oder den Dateipfad) und $context (ein Array mit Kontextinformationen des XML-Parsers). Die Funktion muss entweder eine Ressource (einen geöffneten Stream), einen String (den Inhalt der Entity), oder null zurückgeben, um das Laden abzubrechen.

Besonders wichtig ist diese Funktion im Sicherheitskontext: Mit ihr lässt sich das Laden beliebiger externer Entities gezielt blockieren, was zum Schutz gegen XXE-Angriffe (XML External Entity Injection) unerlässlich ist. Durch Übergabe von null als Argument wird der Standard-Loader wiederhergestellt.

Typische Einsatzgebiete sind das sichere Parsen von nicht vertrauenswürdigen XML-Dokumenten, das selektive Erlauben bestimmter externer Ressourcen sowie das Umleiten von Entity-Anfragen auf lokale Dateien oder Caches.

Parameter

Name Typ Default Beschreibung
$resolver_function Pflicht callable|null Eine Callback-Funktion mit der Signatur function(?string $public, string $system, array $context): resource|string|null, die zur Auflösung externer Entities verwendet wird. Gibt null zurück, um das Laden zu blockieren. Wird null als Argument übergeben, wird der Standard-Loader von libxml wiederhergestellt.

Rückgabewert

Typ
bool
Beschreibung
Gibt true zurück, wenn der Loader erfolgreich gesetzt wurde, andernfalls false.

Beispiele

XXE-Angriffe blockieren durch Deaktivieren des Entity-Loaders

<?php
// Alle externen Entities blockieren – Schutz gegen XXE-Injection
libxml_set_external_entity_loader(function (?string $public, string $system, array $context): ?string {
    // Lädt keine externe Entity – gibt null zurück, um den Vorgang abzubrechen
    trigger_error(
        "Externes Entity-Laden blockiert: system='$system'",
        E_USER_WARNING
    );
    return null;
});

$xml = <<<XML
<?xml version="1.0"?>
<!DOCTYPE test [
  <!ENTITY xxe SYSTEM "file:///etc/passwd">
]>
<root>&xxe;</root>
XML;

$doc = new DOMDocument();
$doc->loadXML($xml, LIBXML_NONET);

echo $doc->documentElement->textContent; // Gibt nichts aus – Entity wurde blockiert
Warning: Externes Entity-Laden blockiert: system='file:///etc/passwd'

Externe Entity auf lokalen Cache umleiten

<?php
// Bestimmte DTD-Anfragen auf lokale Dateien umleiten
libxml_set_external_entity_loader(function (?string $public, string $system, array $context) {
    $allowed = [
        'http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd' => '/var/cache/dtd/xhtml1-strict.dtd',
    ];

    if (isset($allowed[$system]) && file_exists($allowed[$system])) {
        return fopen($allowed[$system], 'r');
    }

    // Alle anderen externen Entities blockieren
    return null;
});

$xml = file_get_contents('/var/www/html/document.xhtml');
$doc = new DOMDocument();
$doc->loadXML($xml);

echo "XML erfolgreich geladen: " . $doc->documentElement->nodeName;
XML erfolgreich geladen: html

Standard-Loader wiederherstellen

<?php
// Zuvor gesetzten Loader entfernen und Standard-Loader wiederherstellen
libxml_set_external_entity_loader(null);
echo "Standard-Loader wiederhergestellt.";
Standard-Loader wiederhergestellt.

// Wichtig · Fallstricke

Sicherheitshinweis – XXE-Injection: Das Laden externer XML-Entities ist eine der häufigsten Angriffsvektoren in PHP-Anwendungen, die XML verarbeiten. Ohne Schutzmaßnahmen können Angreifer über speziell präparierte XML-Dokumente beliebige lokale Dateien auslesen (z. B. /etc/passwd) oder interne Netzwerkressourcen ansprechen (SSRF). Es wird dringend empfohlen, libxml_set_external_entity_loader() einzusetzen und alle externen Entities standardmäßig zu blockieren.

Ab PHP 8.0 ist der externe Entity-Loader standardmäßig deaktiviert, wenn kein Loader gesetzt ist, und gibt eine Warnung aus. In PHP 7.x und darunter musste dieser Schutz manuell aktiviert werden.

Die Funktion wirkt global auf alle libxml-Operationen im aktuellen PHP-Prozess, also auch auf SimpleXML, DOMDocument, XMLReader und xsl_xsltprocessor. Der Callback sollte daher so defensiv wie möglich implementiert werden.

Beim Einsatz in einer Umgebung mit mehreren gleichzeitigen Requests (z. B. Swoole, ReactPHP) ist besondere Vorsicht geboten, da der Loader prozessglobal gesetzt wird und Race Conditions auftreten können.