FlawOpen

flawopen.com/Entités externes XML (XXE)/Sécurité des analyseurs XML Python

xml.etree.ElementTree est-il sûr contre XXE ?

CWE-611 : référence à une entité externe XMLPage de référence
Réponse courte

Pour le XXE classique par fichier ou réseau, les analyseurs Python fondés sur Expat n’accèdent pas aux fichiers locaux et ne créent pas de connexion réseau par défaut. Mais tous les usages XML ne sont pas sûrs : Expat antérieur à 2.7.2 peut subir un DoS par expansion d’entités ou jetons longs. Les valeurs par défaut de lxml varient selon la version. Épinglez et configurez explicitement les analyseurs, ou utilisez defusedxml pour du XML non fiable.

RISQUÉ — version et options modifient l’exposition

XXE (CWE-611) :
L’analyseur résout une entité externe issue d’un XML contrôlé par un attaquant ; cela peut lire des fichiers ou émettre des requêtes serveur.
DoS par expansion d’entités :
Des références imbriquées ou répétées consomment trop de CPU ou de mémoire lors de leur expansion.
Expat :
Analyseur C des modules XML intégrés à Python ; vérifier la version active avec pyexpat.EXPAT_VERSION.
DTD :
Une déclaration de type de document peut définir des entités et, selon la configuration, demander des ressources externes.
Étape 1

Le XML non fiable atteint l’analyseur

Un téléversement, SVG, message SAML ou flux d’intégration franchit la frontière de confiance vers une API XML.

Étape 2

L’implémentation et les options déterminent le comportement

La bibliothèque standard utilise Expat ; lxml utilise libxml2. Version, expansion, accès externe et options déterminent le comportement atteignable.

Étape 3

Résolution ou expansion produit un effet

Si la résolution externe est active, une entité peut demander du contenu local ou distant. Une expansion vulnérable ou de longs jetons peuvent épuiser les ressources.

Étape 4

Les droits du processus bornent l’impact

Droits fichiers et sortie réseau limitent XXE ; taille d’entrée, analyseur corrigé, options sûres et isolation réduisent l’exposition.

Les recommandations Python indiquent qu’Expat n’accède pas aux fichiers locaux et ne crée pas de connexions réseau par défaut. Les versions antérieures à 2.7.2 peuvent toutefois être vulnérables à billion laughs, quadratic blowup, longs jetons ou mémoire disproportionnée. Vérifiez pyexpat.EXPAT_VERSION : Python peut utiliser Expat inclus ou celui du système. Le risque dépend de la version ; cela ne signifie pas que l’ElementTree actuel résout des entités externes.

RENFORCÉ — rejeter DTD et ressources externes
# 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)
Trois risques XML à distinguer
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.

Choisir les options sûres de l’analyseur déployé

Avec defusedxml.ElementTree, déclarations d’entités et références externes sont interdites par défaut ; ajoutez forbid_dtd=True si le format n’a pas besoin de DTD. Pour lxml, définissez resolve_entities=False, load_dtd=False, no_network=True et huge_tree=False. Les versions actuelles ne résolvent que les entités internes par défaut ; avant lxml 5.0, la résolution était activée. N’exécutez pas XInclude sur un arbre non fiable sans chargeur restreint. Limitez la taille avant décompression et analyse : les options ne bornent pas tous les coûts.

Pourquoi revoir les paramètres selon la version

« XML Python » ne correspond pas à une configuration unique. La bibliothèque standard délègue à Expat, inclus ou système selon la compilation. lxml utilise libxml2 et a changé le défaut de résolution des entités dans la version 5.0 ; wrappers et options peuvent encore le modifier. Consignez Python, Expat, lxml et libxml2, puis explicitez les options à chaque point d’entrée non fiable.

Questions fréquentes

ElementTree lit-il des fichiers locaux via des entités externes par défaut ?

Non. Python indique qu’Expat n’accède pas aux fichiers locaux et n’ouvre pas le réseau par défaut. Vérifiez la version et distinguez l’accès XXE des risques d’épuisement des anciens analyseurs.

lxml actuel est-il risqué par défaut ?

Ne généralisez pas entre versions. XMLParser actuel utilise les entités internes, ne charge pas les DTD et n’accède pas au réseau par défaut. resolve_entities est passé de True à internal dans lxml 5.0. Définissez explicitement les options et examinez les wrappers.

defusedxml rejette-t-il toutes les DTD par défaut ?

Non. Entités et références externes sont bloquées, mais forbid_dtd vaut False. Passez-le à True si le format n’a pas besoin de DTD.

Un analyseur sûr supprime-t-il tous les risques de ressources XML ?

Non. Limitez les données comprimées et décomprimées, actualisez les analyseurs, évitez huge_tree et n’exécutez pas XInclude non fiable avec un chargeur sans restriction.

Références principales

À voir aussi Injection d'entité externe XML (XXE, CWE-611) : fonctionnement et prévention — flawopen.com XmlReader de .NET est-il sûr contre XXE ? XXE Java : DocumentBuilderFactory est-elle sûre par défaut ?