flawopen.com/Entidades externas XML (XXE)/Segurança de parsers XML em Python
O xml.etree.ElementTree do Python é seguro contra XXE?
Para XXE clássico de arquivo e rede, os parsers integrados do Python baseados em Expat não acessam arquivos locais nem abrem conexões de rede por padrão. Isso não torna todo uso de XML seguro: versões do Expat anteriores à 2.7.2 podem sofrer DoS por expansão de entidades e tokens grandes. Os padrões do lxml também variam conforme a versão. Fixe e configure explicitamente os parsers ou use defusedxml para XML não confiável.
ARRISCADO — versão e opções do parser alteram a exposição
- XXE (CWE-611):
- O parser resolve uma entidade externa fornecida em XML controlado por atacante, podendo ler arquivos locais ou fazer requisições do servidor.
- DoS por expansão de entidades:
- Referências aninhadas ou repetidas consomem CPU ou memória em excesso durante a expansão.
- Expat:
- Parser C usado pelo XML integrado do Python; verifique a versão ativa com
pyexpat.EXPAT_VERSION. - DTD:
- Declarações de tipo de documento podem definir entidades e, conforme a configuração, solicitar recursos externos.
XML não confiável chega ao parser
Um upload, SVG, mensagem SAML ou payload de integração cruza a fronteira de confiança e chega a uma API XML.
Implementação e opções definem o comportamento
A biblioteca padrão usa Expat; lxml usa libxml2. Versão, expansão de entidades, acesso externo e flags determinam o que pode ocorrer.
Resolução ou expansão produz efeito
Se a resolução externa estiver ativa, uma entidade pode buscar conteúdo local ou remoto. Expansão vulnerável ou tokens grandes podem consumir recursos.
Permissões limitam o impacto
Permissões de arquivo e saída de rede limitam XXE; limites de entrada, parsers atualizados, flags seguras e isolamento reduzem a exposição.
A orientação atual do Python diz que Expat não acessa arquivos locais nem cria conexões de rede por padrão. Também alerta que versões anteriores à 2.7.2 podem sofrer ataques billion-laughs, quadratic-blowup, tokens grandes ou uso desproporcional de memória; confira pyexpat.EXPAT_VERSION, pois Python pode usar Expat incluído ou do sistema. Esse risco de exaustão depende da versão; não prova que ElementTree atual resolva entidades externas.
# 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.
Escolha configurações seguras para o parser implantado
No defusedxml.ElementTree, declarações de entidades e referências externas são bloqueadas por padrão; defina forbid_dtd=True também quando o formato aceito não precisar de DTD. No lxml, defina explicitamente resolve_entities=False, load_dtd=False, no_network=True e huge_tree=False. As versões atuais usam resolução apenas interna por padrão; antes do lxml 5.0, a resolução vinha ativada. Não processe XInclude em árvores não confiáveis sem um loader restrito. Limite o tamanho antes de descompactar e analisar; flags não limitam todos os custos.
- ✓Inventarie todos os pontos de entrada XML e parsers: ElementTree/Expat, lxml/libxml2, SAX/DOM, SVG, SAML, importação de arquivos e etapas posteriores de XInclude.
- ✓Use uma versão suportada de Python com Expat 2.7.2 ou posterior quando disponível; confirme a versão ativa com
pyexpat.EXPAT_VERSION, sem presumir qual cópia está em uso. - ✓Para XML não confiável, use
defusedxml; rejeite DTDs comforbid_dtd=Truequando o esquema não exigir DTD. - ✓Se usar lxml, fixe uma versão mantida e desative explicitamente resolução de entidades, carregamento de DTD, rede e modo huge-tree; não dependa de padrões que mudam.
- ✓Limite o tamanho comprimido e descomprimido, isole a análise quando necessário e teste fixtures benignas de DTD/entidade na CI sem requisições externas.
Por que revisar padrões conforme a versão do parser
“XML em Python” não é uma única configuração. A biblioteca padrão usa Expat, incluído ou do sistema conforme a build do interpretador. lxml usa libxml2 e mudou o padrão de resolução de entidades na versão 5.0; wrappers e opções explícitas podem mudar o comportamento. Registre Python, Expat, lxml e libxml2 no inventário e declare as flags em cada ponto que aceita entrada não confiável.
Perguntas frequentes
Não. A documentação do Python diz que Expat não acessa arquivos locais nem abre conexões de rede por padrão. Confira a versão do Expat e diferencie acesso a entidades externas de riscos de exaustão em versões antigas.
Não generalize entre versões. O XMLParser atual do lxml usa resolução apenas interna, não carrega DTDs e não acessa a rede por padrão. O padrão de resolve_entities mudou de True para internal no lxml 5.0. Defina as opções e revise wrappers.
Não. Os padrões bloqueiam declarações de entidade e referências externas, mas forbid_dtd é False. Use forbid_dtd=True se o formato não precisar de DTD.
Não. Limite o conteúdo comprimido e expandido, mantenha parsers atualizados, evite huge_tree e não execute XInclude não confiável com loader irrestrito.