XML外部实体注入如何禁用外部实体

wen 网络安全 2

本文目录导读:

XML外部实体注入如何禁用外部实体

  1. Java (JAXP, DOM, SAX, StAX)
  2. Python (lxml)
  3. PHP (SimpleXML, DOMDocument)
  4. .NET (C#)
  5. Node.js (sax, libxmljs, fast-xml-parser)
  6. 通用安全配置原则(即使代码已写)
  7. 特殊场景:SOAP、REST API 或第三方库
  8. 总结:最简单的“万能”方法

XML外部实体注入(XXE)是一种利用XML解析器处理外部实体时存在的安全漏洞,要禁用外部实体,核心思路是在XML解析器中关闭外部实体加载DTD处理功能,根据你使用的语言和解析库,具体配置不同,以下是常见语言/库的禁用方法:

Java (JAXP, DOM, SAX, StAX)

关键点: 设置 DocumentBuilderFactorySAXParserFactoryXMLInputFactory 的相应特性。

示例(DocumentBuilderFactory):

DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
// 禁用外部实体(推荐)
dbf.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
// 或者更精细控制:禁用外部通用实体和参数实体
dbf.setFeature("http://xml.org/sax/features/external-general-entities", false);
dbf.setFeature("http://xml.org/sax/features/external-parameter-entities", false);
DocumentBuilder builder = dbf.newDocumentBuilder();

Python (lxml)

关键点: 使用 parser 对象时禁用 load_dtdentity 解析。

from lxml import etree
parser = etree.XMLParser(
    load_dtd=False,          # 禁止加载DTD
    no_network=True,         # 禁止网络访问外部实体
    resolve_entities=False   # 禁止解析外部实体
)
tree = etree.parse(xml_file, parser)

PHP (SimpleXML, DOMDocument)

关键点: 设置 LIBXML_NOENTLIBXML_NONET(推荐用 libxml_disable_entity_loader,但PHP 8+已弃用)。

// 方法一(纯PHP 7及以下兼容)
$old = libxml_disable_entity_loader(true); // 禁用外部实体加载
$xml = simplexml_load_string($xmlContent);
libxml_disable_entity_loader($old);
// 方法二(推荐,使用LIBXML选项)
$xml = simplexml_load_string($xmlContent, 'SimpleXMLElement', LIBXML_NOENT | LIBXML_NONET);
// 或者
$dom = new DOMDocument();
$dom->loadXML($xmlContent, LIBXML_NOENT | LIBXML_NONET);

.NET (C#)

关键点:XmlReaderSettingsDtdProcessing 设置为 ProhibitIgnore

XmlReaderSettings settings = new XmlReaderSettings();
settings.DtdProcessing = DtdProcessing.Prohibit; // 完全禁止DTD处理
// 或 settings.DtdProcessing = DtdProcessing.Ignore; // 忽略DTD但不报错
using (XmlReader reader = XmlReader.Create(xmlStream, settings))
{
    while (reader.Read()) { /* 安全处理 */ }
}

Node.js (sax, libxmljs, fast-xml-parser)

关键点: 关闭实体解析。

  • fast-xml-parser (推荐):
    const parser = new XMLParser({
        processEntities: false,   // 不处理实体(包括外部实体)
        // 或禁止外部实体加载
        // entity: { denyList: ['*'] }
    });
    const json = parser.parse(xmlString);
  • sax-js:
    var sax = require("sax");
    var parser = sax.parser(true, { lowercase: true });
    // sax没有直接禁用外部实体的选项,需手动过滤错误

通用安全配置原则(即使代码已写)

  1. 禁止DTD声明:大多数XXE攻击依赖DTD中的<!ENTITY>声明,直接拒绝DTD最为简单。
  2. 禁止外部引用协议:如 file://, http://, php:// 等。
  3. 使用白名单解析:如果必须允许外部实体,只允许可信任的源(如本地file:路径白名单)。

特殊场景:SOAP、REST API 或第三方库

  • SOAP: 在Web服务框架中设置解析器(如Spring的DocumentBuilderFactory)。
  • JAXB: 设置Unmarshaller的解析器。
  • Logstash/Elasticsearch: 避免使用默认XML解析器,改用安全配置。

最简单的“万能”方法

如果你能控制XML解析器的创建,直接完全禁用DTD处理disallow-doctype-declDtdProcessing.Prohibit)通常最为彻底,因为外部实体声明必须通过DTD来定义,只有当你确实需要解析业务所需的DTD片段时,才选择更细粒度的禁用外部实体功能。

抱歉,评论功能暂时关闭!