flawopen.com/Entités externes XML (XXE)/Sécurité des analyseurs XML Python
xml.etree.ElementTree est-il sûr contre XXE ?
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.
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.
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.
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.
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.
# 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.
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.
- ✓Inventoriez chaque entrée XML et analyseur : ElementTree/Expat, lxml/libxml2, SAX/DOM, SVG, SAML, import d’archives et toute étape XInclude ultérieure.
- ✓Utilisez Python pris en charge avec Expat 2.7.2 ou ultérieur si disponible ; vérifiez avec
pyexpat.EXPAT_VERSIONau lieu de supposer quelle copie est active. - ✓Pour le XML non fiable, utilisez
defusedxml; rejetez les DTD avecforbid_dtd=Truesi le schéma n’en a pas besoin. - ✓Avec lxml, épinglez une version maintenue et désactivez explicitement entités, DTD, réseau et huge-tree ; ne dépendez pas des valeurs par défaut changeantes.
- ✓Limitez taille compressée et décompressée, isolez l’analyse si nécessaire et testez des cas DTD/entité inoffensifs en CI sans requête externe.
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
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.
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.
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.
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.