xml bomb是一种利用xml解析器过度忠实展开dtd实体导致内存耗尽的攻击。其根源在于解析器默认启用dtd和外部实体,需显式禁用相关功能来防御。

XML Bomb 是什么?它不是“被黑了”,是解析器老实过头了
XML Bomb(十亿笑弹攻击)不是黑客发了巨量请求,而是用几百字节的恶意 XML,骗解析器自己把内存撑爆。根源在于:只要 DTD 被允许、实体展开没限制,解析器就会忠实地递归展开 &a; → &b; → &c;……直到 OOM。这不是代码逻辑漏洞,是配置失守——就像给门装了锁,却把钥匙焊死在门把手上。
Java 中用 SAX/DOM 解析 XML 时,默认就是炸弹引信
Java 的 DocumentBuilder 和 SAXParser 在 JDK 8 及更早版本中,默认启用 DTD 和外部实体。哪怕你只调用 parse(InputStream),没碰任何安全开关,就已经暴露。
- 必须显式禁用 DTD:
setFeature("http://apache.org/xml/features/disallow-doctype-decl", true) - 必须关闭外部实体:
setFeature("http://xml.org/sax/features/external-general-entities", false)和setFeature("http://xml.org/sax/features/external-parameter-entities", false) - 别信“我只解析内部数据”——只要接口接收用户输入(如上传 XML 配置、SOAP 请求体),就属于不可信源
.NET 中 XmlReaderSettings 不设 DtdProcessing.Prohibit 就等于开门
在 .NET Framework 或 .NET Core 中,XmlReader.Create() 若直接传入原始字符串或流,且未配 XmlReaderSettings,默认会处理 DTD——哪怕你用的是 MSXML 6.0 或 System.Xml v4.8+。
- 关键一步:
settings.DtdProcessing = DtdProcessing.Prohibit(不是Ignore,Ignore仍可能触发部分解析) - 同时设
settings.XmlResolver = null,堵死外部实体加载路径 - 若需兼容旧系统又不能改解析逻辑,至少加
settings.MaxCharactersFromEntities = 10240(单位:字符),防浅层爆炸
Python 的 xml.etree.ElementTree 也危险,别被“标准库”误导
xml.etree.ElementTree.parse() 在 Python 3.9 之前默认允许 DTD;3.10+ 虽默认禁用外部实体,但 DTD 声明本身仍被读取(可能触发警告或异常,但不阻止解析)。更麻烦的是,很多项目混用 lxml(基于 libxml2),而它默认开启全部 DTD 功能。
- 安全写法:
parser = XMLParser(resolve_entities=False)+parse(file, parser) - 用
lxml时必须:parser = etree.XMLParser(resolve_entities=False, no_network=True, dtd_validation=False) - 永远不要对用户输入调用
etree.fromstring(xml_str)—— 它不校验、不设限、不警告
最常被忽略的一点:防御不是靠“识别恶意 XML”,而是让解析器从第一行就拒绝执行 DTD。所有“先解析再校验”的方案,都已在内存爆炸的途中。










