FlawOpen

flawopen.com/XML External Entities (XXE)/Sicherheit von Python-XML-Parsern

Ist Python xml.etree.ElementTree vor XXE sicher?

CWE-611: XML External Entity ReferenceReferenzseite
Kurzantwort

Gegen klassisches Datei- und Netzwerk-XXE greifen Pythons eingebaute Expat-Parser standardmäßig nicht auf lokale Dateien zu und öffnen keine Netzwerkverbindungen. Das macht nicht jede XML-Verarbeitung sicher: Expat vor 2.7.2 kann durch Entity-Erweiterung und lange Tokens DoS-anfällig sein. lxml-Defaults hängen ebenfalls von der Version ab. Fixiere und konfiguriere Parser ausdrücklich oder nutze defusedxml für nicht vertrauenswürdiges XML.

RISKANT — Version und Optionen bestimmen die Angriffsfläche

XXE (CWE-611):
Der Parser löst eine externe Entity aus angreiferkontrolliertem XML auf und kann lokale Dateien lesen oder Serveranfragen stellen.
DoS durch Entity-Erweiterung:
Verschachtelte oder wiederholte Referenzen verbrauchen beim Erweitern unverhältnismäßig CPU oder Speicher.
Expat:
C-Parser der integrierten Python-XML-Module; aktive Version mit pyexpat.EXPAT_VERSION prüfen.
DTD:
Eine Dokumenttypdeklaration kann Entities definieren und je nach Einstellung externe Ressourcen anfordern.
Schritt 1

Nicht vertrauenswürdiges XML erreicht den Parser

Upload, SVG, SAML-Nachricht oder Integrationsdaten überschreiten die Vertrauensgrenze zu einer XML-API.

Schritt 2

Implementierung und Optionen bestimmen das Verhalten

Die Standardbibliothek nutzt Expat, lxml nutzt libxml2. Version, externe Auflösung, Erweiterung und Flags bestimmen erreichbares Verhalten.

Schritt 3

Auflösung oder Erweiterung wirkt sich aus

Bei externer Auflösung kann eine Entity lokale oder entfernte Inhalte anfordern. Verwundbare Erweiterung oder lange Tokens können Ressourcen aufbrauchen.

Schritt 4

Prozessrechte begrenzen Folgen

Dateirechte und Netzwerk-Egress begrenzen XXE; Eingabelimits, aktualisierte Parser, sichere Flags und Isolation senken das Risiko.

Die aktuelle Python-Anleitung sagt, dass Expat standardmäßig keine lokalen Dateien liest und keine Netzwerkverbindungen öffnet. Expat-Versionen vor 2.7.2 können jedoch von Billion-Laughs, Quadratic-Blowup, langen Tokens oder unverhältnismäßigem Speicherverbrauch betroffen sein. Prüfe pyexpat.EXPAT_VERSION, denn Python kann gebündeltes oder System-Expat nutzen. Das ist versionsabhängiges Ressourcenrisiko und kein Beleg, dass aktuelles ElementTree externe Entities auflöst.

GESPERRT — DTDs und externe Ressourcen ablehnen
# Standard-library external access is off by default,
# but old Expat builds have resource-exhaustion risks.
import xml.etree.ElementTree as ET
from xml.parsers import expat

print(expat.EXPAT_VERSION)  # inspect the runtime parser
root = ET.fromstring(untrusted_xml)

# lxml before 5.0 defaulted resolve_entities=True.
# Explicit unsafe settings illustrate the risky boundary.
from lxml import etree
parser = etree.XMLParser(resolve_entities=True, load_dtd=True)
root = etree.fromstring(untrusted_xml, parser)
Drei XML-Parser-Risiken unterscheiden
from defusedxml.ElementTree import fromstring

# Reject DTD declarations when the format does not require them.
root = fromstring(untrusted_xml, forbid_dtd=True)

# If lxml is required, set its security options explicitly.
from lxml import etree
parser = etree.XMLParser(
    resolve_entities=False,
    no_network=True,
    load_dtd=False,
    huge_tree=False,
)
root = etree.fromstring(untrusted_xml, parser)
# Do not run XInclude on untrusted trees without a restricted loader.

Sichere Optionen des tatsächlich eingesetzten Parsers wählen

Bei defusedxml.ElementTree sind Entity-Deklarationen und externe Referenzen standardmäßig verboten; setze zusätzlich forbid_dtd=True, wenn das Format keine DTD benötigt. Bei lxml explizit resolve_entities=False, load_dtd=False, no_network=True und huge_tree=False setzen. Aktuelle Versionen lösen standardmäßig nur interne Entities auf; vor lxml 5.0 war die Auflösung aktiv. Kein XInclude auf nicht vertrauenswürdigen Bäumen ohne eingeschränkten Loader. Begrenze Größe vor Dekompression und Parsing; Flags begrenzen nicht alle Kosten.

Warum Parser-Defaults versionsabhängig geprüft werden müssen

„Python-XML“ ist keine einheitliche Parserkonfiguration. Die Standardbibliothek verwendet Expat, je nach Interpreter-Build gebündelt oder systemweit. lxml nutzt libxml2 und änderte den Entity-Default in Version 5.0; Wrapper und Optionen ändern Verhalten zusätzlich. Erfasse Python-, Expat-, lxml- und libxml2-Versionen und setze Sicherheitsflags an jeder Stelle mit nicht vertrauenswürdiger Eingabe explizit.

Häufige Fragen

Liest ElementTree standardmäßig lokale Dateien über externe Entities?

Nein. Python dokumentiert, dass Expat standardmäßig keine lokalen Dateien liest und kein Netzwerk öffnet. Prüfe die Version und unterscheide XXE-Dateizugriff von Ressourcenrisiken älterer Parser.

Ist aktuelles lxml standardmäßig unsicher?

Nicht über alle Versionen verallgemeinern. Aktuelles XMLParser löst standardmäßig nur interne Entities auf, lädt keine DTDs und nutzt kein Netzwerk. resolve_entities wechselte in lxml 5.0 von True zu internal. Optionen ausdrücklich setzen und Wrapper prüfen.

Lehnt defusedxml standardmäßig alle DTDs ab?

Nein. Entities und externe Referenzen sind verboten, aber forbid_dtd ist False. Setze es auf True, wenn das Format keine DTD benötigt.

Beseitigt ein sicherer Parser alle XML-Ressourcenrisiken?

Nein. Begrenze komprimierte und dekomprimierte Eingaben, aktualisiere Parser, vermeide huge_tree und führe XInclude bei nicht vertrauenswürdigem XML nicht mit uneingeschränktem Loader aus.

Primärquellen

Siehe auch XML External Entity Injection (XXE, CWE-611): Funktionsweise und Schutz — flawopen.com Ist .NET XmlReader gegen XXE geschützt? Java-XXE: Ist DocumentBuilderFactory standardmäßig sicher?