flawopen.com/XML External Entities (XXE)/Sicherheit von Python-XML-Parsern
Ist Python xml.etree.ElementTree vor XXE sicher?
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_VERSIONprüfen. - DTD:
- Eine Dokumenttypdeklaration kann Entities definieren und je nach Einstellung externe Ressourcen anfordern.
Nicht vertrauenswürdiges XML erreicht den Parser
Upload, SVG, SAML-Nachricht oder Integrationsdaten überschreiten die Vertrauensgrenze zu einer XML-API.
Implementierung und Optionen bestimmen das Verhalten
Die Standardbibliothek nutzt Expat, lxml nutzt libxml2. Version, externe Auflösung, Erweiterung und Flags bestimmen erreichbares Verhalten.
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.
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.
# 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)
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.
- ✓Inventarisiere jeden XML-Eingang und Parser: ElementTree/Expat, lxml/libxml2, SAX/DOM, SVG, SAML, Archivimporte und nachgelagerte XInclude-Schritte.
- ✓Nutze unterstütztes Python mit Expat 2.7.2 oder neuer, sofern verfügbar; prüfe mit
pyexpat.EXPAT_VERSION, welche Version aktiv ist. - ✓Nutze für nicht vertrauenswürdiges XML
defusedxml; lehne DTDs mitforbid_dtd=Trueab, wenn das Schema sie nicht braucht. - ✓Bei lxml eine gepflegte Version fixieren und Entity-Auflösung, DTD-Laden, Netzwerk und huge-tree ausdrücklich abschalten; nicht auf wechselnde Defaults vertrauen.
- ✓Begrenze komprimierte und dekomprimierte Größe, isoliere Parsing nach Bedarf und teste harmlose DTD-/Entity-Fälle in CI ohne externe Anfragen.
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
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.
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.
Nein. Entities und externe Referenzen sind verboten, aber forbid_dtd ist False. Setze es auf True, wenn das Format keine DTD benötigt.
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.