跳到内容

XML 外部实体预防速查表

简介

XML 外部实体注入 (XXE) 现已通过 A4 点纳入 OWASP Top 10,它是针对解析 XML 输入的应用程序的一种攻击。此问题在 通用弱点枚举 参考中的 ID 611 中被引用。当不受信任的 XML 输入包含一个对外部实体的引用,并由配置薄弱的 XML 解析器处理时,就会发生 XXE 攻击,这种攻击可用于引发多种事件,包括:

  • 对系统的拒绝服务攻击
  • 服务器端请求伪造 (SSRF) 攻击
  • 从解析器所在机器扫描端口的能力
  • 其他系统影响。

本速查表将帮助您预防此漏洞。

有关 XXE 的更多信息,请访问 XML 外部实体 (XXE)

通用指南

预防 XXE 最安全的方法始终是完全禁用 DTD(外部实体)。 根据解析器不同,方法应类似于以下内容:

factory.setFeature("https://apache.ac.cn/xml/features/disallow-doctype-decl", true);

禁用 DTD 还能使解析器抵御拒绝服务 (DOS) 攻击,例如 十亿笑攻击如果无法完全禁用 DTD,则必须以针对每个解析器的特定方式禁用外部实体和外部文档类型声明。

下面提供了针对多种语言(C++、Cold Fusion、Java、.NET、iOS、PHP、Python、Semgrep 规则)及其常用 XML 解析器的详细 XXE 预防指南。

C/C++

libxml2

枚举 xmlParserOption 不应定义以下选项:

  • XML_PARSE_NOENT: 扩展实体并用替换文本代替
  • XML_PARSE_DTDLOAD: 加载外部 DTD

注意

根据:这篇帖子,从 libxml2 版本 2.9 开始,XXE 默认已被禁用,如以下 补丁 所示。

搜索是否正在使用以下 API,并确保参数中未定义 XML_PARSE_NOENTXML_PARSE_DTDLOAD

  • xmlCtxtReadDoc
  • xmlCtxtReadFd
  • xmlCtxtReadFile
  • xmlCtxtReadIO
  • xmlCtxtReadMemory
  • xmlCtxtUseOptions
  • xmlParseInNodeContext
  • xmlReadDoc
  • xmlReadFd
  • xmlReadFile
  • xmlReadIO
  • xmlReadMemory

libxerces-c

使用 XercesDOMParser 执行此操作以防止 XXE

XercesDOMParser *parser = new XercesDOMParser;
parser->setCreateEntityReferenceNodes(true);
parser->setDisableDefaultEntityResolution(true);

使用 SAXParser,执行此操作以防止 XXE

SAXParser* parser = new SAXParser;
parser->setDisableDefaultEntityResolution(true);

使用 SAX2XMLReader,执行此操作以防止 XXE

SAX2XMLReader* reader = XMLReaderFactory::createXMLReader();
parser->setFeature(XMLUni::fgXercesDisableDefaultEntityResolution, true);

ColdFusion

根据 这篇博客文章,Adobe ColdFusion 和 Lucee 都内置了禁用对外部 XML 实体支持的机制。

Adobe ColdFusion

从 ColdFusion 2018 Update 14 和 ColdFusion 2021 Update 4 开始,所有处理 XML 的原生 ColdFusion 函数都带有一个 XML 解析器参数,该参数禁用对外部 XML 实体的支持。由于没有禁用外部实体的全局设置,开发人员必须确保每个 XML 函数调用都使用正确的安全选项。

根据 XmlParse() 函数的文档,您可以使用以下代码禁用 XXE:

<cfset parseroptions = structnew()>
<cfset parseroptions.ALLOWEXTERNALENTITIES = false>
<cfscript>
a = XmlParse("xml.xml", false, parseroptions);
writeDump(a);
</cfscript>

您可以使用上面所示的 "parseroptions" 结构作为参数来保护其他处理 XML 的函数,例如:

XxmlSearch(xmldoc, xpath,parseroptions);

XmlTransform(xmldoc,xslt,parseroptions);

isXML(xmldoc,parseroptions);

Lucee

从 Lucee 5.3.4.51 及更高版本开始,您可以通过在 Application.cfc 中添加以下内容来禁用对 XML 外部实体的支持:

this.xmlFeatures = {
     externalGeneralEntities: false,
     secure: true,
     disallowDoctypeDecl: true
};

从 Lucee 5.4.2.10 和 Lucee 6.0.0.514 开始,默认禁用对外部 XML 实体的支持。

Java

由于大多数 Java XML 解析器默认启用 XXE,因此这种语言特别容易受到 XXE 攻击,所以您必须明确禁用 XXE 才能安全地使用这些解析器。本节描述了如何在最常用的 Java XML 解析器中禁用 XXE。

JAXP DocumentBuilderFactory, SAXParserFactory 和 DOM4J

DocumentBuilderFactorySAXParserFactoryDOM4J XML 解析器可以使用相同的技术抵御 XXE 攻击。

为简洁起见,我们仅演示如何保护 DocumentBuilderFactory 解析器。保护此解析器的附加说明嵌入在示例代码中:

JAXP DocumentBuilderFactorysetFeature 方法允许开发人员控制启用或禁用哪些特定于实现的 XML 处理器功能。

这些功能可以在工厂上设置,也可以在底层的 XMLReader setFeature 方法上设置。

每个 XML 处理器实现都有自己的功能,控制如何处理 DTD 和外部实体。通过完全禁用 DTD 处理,可以避免大多数 XXE 攻击,但同时也有必要禁用或验证 XInclude 是否未启用。

从 JDK 6 开始,可以使用标志 FEATURE_SECURE_PROCESSING 来指示解析器的实现以安全方式处理 XML。其行为取决于实现。它可能有助于资源耗尽问题,但可能无法始终缓解实体扩展。有关此标志的更多详细信息,请参见 此处

有关使用 SAXParserFactory 的语法高亮示例代码片段,请查看 此处。完全禁用 DTD(文档类型)的示例代码:

import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException; // catching unsupported features
import javax.xml.XMLConstants;

...

DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
String FEATURE = null;
try {
    // This is the PRIMARY defense. If DTDs (doctypes) are disallowed, almost all
    // XML entity attacks are prevented
    // Xerces 2 only - http://xerces.apache.org/xerces2-j/features.html#disallow-doctype-decl
    FEATURE = "https://apache.ac.cn/xml/features/disallow-doctype-decl";
    dbf.setFeature(FEATURE, true);

    // and these as well, per Timothy Morgan's 2014 paper: "XML Schema, DTD, and Entity Attacks"
    dbf.setXIncludeAware(false);

    // remaining parser logic
    ...
} catch (ParserConfigurationException e) {
    // This should catch a failed setFeature feature
    // NOTE: Each call to setFeature() should be in its own try/catch otherwise subsequent calls will be skipped.
    // This is only important if you're ignoring errors for multi-provider support.
    logger.info("ParserConfigurationException was thrown. The feature '" + FEATURE
    + "' is not supported by your XML processor.");
    ...
} catch (SAXException e) {
    // On Apache, this should be thrown when disallowing DOCTYPE
    logger.warning("A DOCTYPE was passed into the XML document");
    ...
} catch (IOException e) {
    // XXE that points to a file that doesn't exist
    logger.error("IOException occurred, XXE may still possible: " + e.getMessage());
    ...
}

// Load XML file or stream using a XXE agnostic configured parser...
DocumentBuilder safebuilder = dbf.newDocumentBuilder();

如果您无法完全禁用 DTD

import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException; // catching unsupported features
import javax.xml.XMLConstants;

...

DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();

String[] featuresToDisable = {
    // Xerces 1 - http://xerces.apache.org/xerces-j/features.html#external-general-entities
    // Xerces 2 - http://xerces.apache.org/xerces2-j/features.html#external-general-entities
    // JDK7+ - http://xml.org/sax/features/external-general-entities
    //This feature has to be used together with the following one, otherwise it will not protect you from XXE for sure
    "http://xml.org/sax/features/external-general-entities",

    // Xerces 1 - http://xerces.apache.org/xerces-j/features.html#external-parameter-entities
    // Xerces 2 - http://xerces.apache.org/xerces2-j/features.html#external-parameter-entities
    // JDK7+ - http://xml.org/sax/features/external-parameter-entities
    //This feature has to be used together with the previous one, otherwise it will not protect you from XXE for sure
    "http://xml.org/sax/features/external-parameter-entities",

    // Disable external DTDs as well
    "https://apache.ac.cn/xml/features/nonvalidating/load-external-dtd"
}

for (String feature : featuresToDisable) {
    try {    
        dbf.setFeature(FEATURE, false); 
    } catch (ParserConfigurationException e) {
        // This should catch a failed setFeature feature
        logger.info("ParserConfigurationException was thrown. The feature '" + feature
        + "' is probably not supported by your XML processor.");
        ...
    }
}

try {
    // Add these as per Timothy Morgan's 2014 paper: "XML Schema, DTD, and Entity Attacks"
    dbf.setXIncludeAware(false);
    dbf.setExpandEntityReferences(false);

    // As stated in the documentation, "Feature for Secure Processing (FSP)" is the central mechanism that will
    // help you safeguard XML processing. It instructs XML processors, such as parsers, validators, 
    // and transformers, to try and process XML securely, and the FSP can be used as an alternative to
    // dbf.setExpandEntityReferences(false); to allow some safe level of Entity Expansion
    // Exists from JDK6.
    dbf.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);

    // And, per Timothy Morgan: "If for some reason support for inline DOCTYPEs are a requirement, then
    // ensure the entity settings are disabled (as shown above) and beware that SSRF attacks
    // (http://cwe.mitre.org/data/definitions/918.html) and denial
    // of service attacks (such as billion laughs or decompression bombs via "jar:") are a risk."

    // remaining parser logic
    ...
} catch (ParserConfigurationException e) {
    // This should catch a failed setFeature feature
    logger.info("ParserConfigurationException was thrown. The feature 'XMLConstants.FEATURE_SECURE_PROCESSING'"
    + " is probably not supported by your XML processor.");
    ...
} catch (SAXException e) {
    // On Apache, this should be thrown when disallowing DOCTYPE
    logger.warning("A DOCTYPE was passed into the XML document");
    ...
} catch (IOException e) {
    // XXE that points to a file that doesn't exist
    logger.error("IOException occurred, XXE may still possible: " + e.getMessage());
    ...
}

// Load XML file or stream using a XXE agnostic configured parser...
DocumentBuilder safebuilder = dbf.newDocumentBuilder();

Xerces 1 功能

  • 通过将 此功能 设置为 false,不包含外部实体。
  • 通过将 此功能 设置为 false,不包含参数实体。
  • 通过将 此功能 设置为 false,不包含外部 DTD。

Xerces 2 功能

  • 通过将 此功能 设置为 true,禁止内联 DTD。
  • 通过将 此功能 设置为 false,不包含外部实体。
  • 通过将 此功能 设置为 false,不包含参数实体。
  • 通过将 此功能 设置为 false,不包含外部 DTD。

注意:上述防御措施需要 Java 7 update 67、Java 8 update 20 或更高版本,因为根据 CVE-2014-6517DocumentBuilderFactory 和 SAXParserFactory 的对策在早期 Java 版本中存在问题。

XMLInputFactory (StAX 解析器)

StAX 解析器,例如 XMLInputFactory,允许设置各种属性和功能。

为了保护 Java XMLInputFactory 免受 XXE 攻击,请完全禁用 DTD(文档类型)

// This disables DTDs entirely for that factory
xmlInputFactory.setProperty(XMLInputFactory.SUPPORT_DTD, false);

或者,如果您无法完全禁用 DTD

// This causes XMLStreamException to be thrown if external DTDs are accessed.
xmlInputFactory.setProperty(XMLConstants.ACCESS_EXTERNAL_DTD, "");
// disable external entities
xmlInputFactory.setProperty("javax.xml.stream.isSupportingExternalEntities", false);

xmlInputFactory.setProperty(XMLConstants.ACCESS_EXTERNAL_SCHEMA, ""); 此设置不是必需的,因为 XMLInputFactory 依赖于 Validator 对 Schema 执行 XML 验证。有关具体配置,请检查Validator部分。

Oracle DOM 解析器

遵循 Oracle 建议 例如

    // Extend oracle.xml.parser.v2.XMLParser
    DOMParser domParser = new DOMParser();

    // Do not expand entity references
    domParser.setAttribute(DOMParser.EXPAND_ENTITYREF, false);

    // dtdObj is an instance of oracle.xml.parser.v2.DTD
    domParser.setAttribute(DOMParser.DTD_OBJECT, dtdObj);

    // Do not allow more than 11 levels of entity expansion
    domParser.setAttribute(DOMParser.ENTITY_EXPANSION_DEPTH, 12);

TransformerFactory

为了保护 javax.xml.transform.TransformerFactory 免受 XXE 攻击,请执行以下操作:

TransformerFactory tf = TransformerFactory.newInstance();
tf.setAttribute(XMLConstants.ACCESS_EXTERNAL_DTD, "");
tf.setAttribute(XMLConstants.ACCESS_EXTERNAL_STYLESHEET, "");

Validator

为了保护 javax.xml.validation.Validator 免受 XXE 攻击,请执行以下操作:

SchemaFactory factory = SchemaFactory.newInstance("http://www.w3.org/2001/XMLSchema");
factory.setProperty(XMLConstants.ACCESS_EXTERNAL_DTD, "");
factory.setProperty(XMLConstants.ACCESS_EXTERNAL_SCHEMA, "");
Schema schema = factory.newSchema();
Validator validator = schema.newValidator();
validator.setProperty(XMLConstants.ACCESS_EXTERNAL_DTD, "");
validator.setProperty(XMLConstants.ACCESS_EXTERNAL_SCHEMA, "");

SchemaFactory

为了保护 javax.xml.validation.SchemaFactory 免受 XXE 攻击,请执行以下操作:

SchemaFactory factory = SchemaFactory.newInstance("http://www.w3.org/2001/XMLSchema");
factory.setProperty(XMLConstants.ACCESS_EXTERNAL_DTD, "");
factory.setProperty(XMLConstants.ACCESS_EXTERNAL_SCHEMA, "");
Schema schema = factory.newSchema(Source);

SAXTransformerFactory

为了保护 javax.xml.transform.sax.SAXTransformerFactory 免受 XXE 攻击,请执行以下操作:

SAXTransformerFactory sf = SAXTransformerFactory.newInstance();
sf.setAttribute(XMLConstants.ACCESS_EXTERNAL_DTD, "");
sf.setAttribute(XMLConstants.ACCESS_EXTERNAL_STYLESHEET, "");
sf.newXMLFilter(Source);

注意:使用以下 XMLConstants 需要 JAXP 1.5,该版本已在 Java 7u40 和 Java 8 中添加

  • javax.xml.XMLConstants.ACCESS_EXTERNAL_DTD
  • javax.xml.XMLConstants.ACCESS_EXTERNAL_SCHEMA
  • javax.xml.XMLConstants.ACCESS_EXTERNAL_STYLESHEET

XMLReader

为保护 Java org.xml.sax.XMLReader 免受 XXE 攻击,请执行以下操作:

XMLReader reader = XMLReaderFactory.createXMLReader();
reader.setFeature("https://apache.ac.cn/xml/features/disallow-doctype-decl", true);
// This may not be strictly required as DTDs shouldn't be allowed at all, per previous line.
reader.setFeature("https://apache.ac.cn/xml/features/nonvalidating/load-external-dtd", false);
reader.setFeature("http://xml.org/sax/features/external-general-entities", false);
reader.setFeature("http://xml.org/sax/features/external-parameter-entities", false);

SAXReader

为保护 Java org.dom4j.io.SAXReader 免受 XXE 攻击,请执行以下操作:

saxReader.setFeature("https://apache.ac.cn/xml/features/disallow-doctype-decl", true);
saxReader.setFeature("http://xml.org/sax/features/external-general-entities", false);
saxReader.setFeature("http://xml.org/sax/features/external-parameter-entities", false);

如果您的代码没有所有这些行,您可能容易受到 XXE 攻击。

SAXBuilder

为保护 Java org.jdom2.input.SAXBuilder 免受 XXE 攻击,请完全禁用 DTD(文档类型)

SAXBuilder builder = new SAXBuilder();
builder.setFeature("https://apache.ac.cn/xml/features/disallow-doctype-decl",true);
Document doc = builder.build(new File(fileName));

或者,如果 DTD 无法完全禁用,则禁用外部实体和实体扩展

SAXBuilder builder = new SAXBuilder();
builder.setFeature("http://xml.org/sax/features/external-general-entities", false);
builder.setFeature("http://xml.org/sax/features/external-parameter-entities", false);
builder.setFeature("https://apache.ac.cn/xml/features/nonvalidating/load-external-dtd", false);
builder.setExpandEntities(false);
Document doc = builder.build(new File(fileName));

No-op EntityResolver

对于接受 EntityResolver 的 API,您可以通过提供一个无操作的实现来中和 XML 解析器解析实体的能力。

public final class NoOpEntityResolver implements EntityResolver {
    public InputSource resolveEntity(String publicId, String systemId) {
        return new InputSource(new StringReader(""));
    }
}

// ...

xmlReader.setEntityResolver(new NoOpEntityResolver());
documentBuilder.setEntityResolver(new NoOpEntityResolver());

或者更简单地

EntityResolver noop = (publicId, systemId) -> new InputSource(new StringReader(""));
xmlReader.setEntityResolver(noop);
documentBuilder.setEntityResolver(noop);

JAXB Unmarshaller

您应确保 javax.xml.bind.Unmarshallerunmarshal 函数的源是使用具有安全属性(即 XMLInputFactory.SUPPORT_DTDXMLInputFactory.IS_SUPPORTING_EXTERNAL_ENTITIES 设置为 false)的 javax.xml.stream.XMLInputFactory 生成的 javax.xml.stream.XMLStreamReader例如:

File file = new File(xmlPath);
XMLInputFactory xif = XMLInputFactory.newFactory();
xif.setProperty(XMLInputFactory.SUPPORT_DTD, false);
xif.setProperty(XMLInputFactory.IS_SUPPORTING_EXTERNAL_ENTITIES, false);
XMLStreamReader xsr = null;
try {
    xsr = xif.createXMLStreamReader(new StreamSource(file));
} catch (XMLStreamException e) {
    throw new RuntimeException(e);
}  
Unmarshaller um = jc.createUnmarshaller();
um.unmarshal(xsr);

请注意,createXMLStreamReaderunmarshal 方法都有多个带不同源类型的重载,因此您需要选择正确的重载并进行可能的转换。

XPathExpression

由于 javax.xml.xpath.XPathExpression 无法单独进行安全配置,因此必须先通过另一个可安全配置的 XML 解析器解析不受信任的数据。

例如:

DocumentBuilderFactory df = DocumentBuilderFactory.newInstance();
df.setAttribute(XMLConstants.ACCESS_EXTERNAL_DTD, "");
df.setAttribute(XMLConstants.ACCESS_EXTERNAL_SCHEMA, "");
DocumentBuilder builder = df.newDocumentBuilder();
String result = new XPathExpression().evaluate( builder.parse(
                            new ByteArrayInputStream(xml.getBytes())) );

java.beans.XMLDecoder

此类的 readObject() 方法从根本上说是不安全的。

它解析的 XML 不仅受 XXE 影响,而且该方法还可用于构造任何 Java 对象,并执行此处描述的任意代码

除了信任或正确验证传入的输入外,没有办法安全地使用此类别。

因此,我们强烈建议完全避免使用此类,并将其替换为本速查表其他地方描述的安全或正确配置的 XML 解析器。

其他 XML 解析器

有许多第三方库直接或通过使用其他库来解析 XML。请测试并验证它们的 XML 解析器默认是否安全,能够抵御 XXE 攻击。如果解析器默认不安全,请查找解析器支持的标志,以禁用所有可能的外部资源包含,如上面给出的示例。如果外部没有暴露任何控制,请确保不受信任的内容首先通过安全解析器进行解析,然后才传递给不安全的第三方解析器,类似于 Unmarshaller 的安全处理方式。

Spring Framework MVC/OXM XXE 漏洞

**在 Spring OXMSpring MVC 中发现了一些 XXE 漏洞。以下版本的 Spring Framework 容易受到 XXE 攻击:

  • 3.0.03.2.3 (Spring OXM & Spring MVC)
  • 4.0.0.M1 (Spring OXM)
  • 4.0.0.M1-4.0.0.M2 (Spring MVC)

还有其他问题后来也得到了修复,因此为了彻底解决这些问题,Spring 建议您升级到 Spring Framework 3.2.8+ 或 4.0.2+。

对于 Spring OXM,这里指的是 org.springframework.oxm.jaxb.Jaxb2Marshaller 的使用。请注意,Spring OXM 的 CVE 明确指出,两种 XML 解析情况需要开发人员正确处理,而另外两种情况是 Spring 的责任,并已修复以解决此 CVE。

他们是这样说的:

开发人员必须处理的两种情况

  • 对于 DOMSource,XML 已由用户代码解析,该代码负责防范 XXE。
  • 对于 StAXSourceXMLStreamReader 已由用户代码创建,该代码负责防范 XXE。

Spring 修复的问题

对于 SAXSource 和 StreamSource 实例,Spring 默认处理外部实体,从而产生了此漏洞。

以下是使用易受攻击但现在安全的 StreamSource 的示例,如果您使用的是已修复的 Spring OXM 或 Spring MVC 版本:

import org.springframework.oxm.Jaxb2Marshaller;
import org.springframework.oxm.jaxb.Jaxb2Marshaller;

Jaxb2Marshaller marshaller = new Jaxb2Marshaller();
// Must cast return Object to whatever type you are unmarshalling
marshaller.unmarshal(new StreamSource(new StringReader(some_string_containing_XML));

因此,根据 Spring OXM CVE 撰写,上述内容现在是安全的。但如果您使用 DOMSource 或 StAXSource,则需要您自行配置这些源以确保其免受 XXE 攻击。

Castor

Castor 是一个用于 Java 的数据绑定框架。它允许在 Java 对象、XML 和关系表之间进行转换。Castor 1.3.3 版本之前的 XML 功能容易受到 XXE 攻击,应升级到最新版本。有关更多信息,请查看官方的 XML 配置文件

.NET

.NET 中 XXE 注入的最新信息直接取自 Dean Fleming 的单元测试 Web 应用程序,该应用程序涵盖了所有当前支持的 .NET XML 解析器,并具有测试用例,演示了它们何时安全免受 XXE 注入,何时不安全,但这些测试仅针对文件注入,而不包括直接 DTD(用于 DoS 攻击)注入。

对于使用直接 DTD 的 DoS 攻击(例如 十亿笑攻击),已创建了一个 由 Bounce Security 的 Josh Grossman 提供的单独测试应用程序,以验证 .NET >=4.5.2 是否免受这些攻击。

此前,此信息基于一些可能不完全准确的旧文章,包括:

.NET 解析器安全级别概述

**以下是所有受支持的 .NET XML 解析器及其默认安全级别的概述。有关每个解析器的更多详细信息,请在此列表之后提供。

**XDocument (LINQ to XML)

此解析器在 .NET Framework 4.5.2 版中受外部实体保护,在 4.5.2 版或更高版本中受十亿笑攻击保护,但尚不确定此解析器在 4.5.2 版之前是否受十亿笑攻击保护。

XmlDocument, XmlTextReader, XPathNavigator 默认安全级别

这些解析器在版本低于 4.5.2 时容易受到外部实体攻击和十亿笑攻击,但在版本等于或高于 4.5.2 时受保护。

XmlDictionaryReader, XmlNodeReader, XmlReader 默认安全级别

这些解析器在 4.5.2 版本之前或之后均不易受到外部实体攻击或十亿笑攻击。此外,在 ≥4.5.2 版本及更高版本中,这些库默认甚至不会处理内联 DTD。即使您更改默认设置以允许处理 DTD,如果发生 DoS 尝试,仍会抛出异常,如上文所述。

ASP.NET

ASP.NET 应用程序 ≥ .NET 4.5.2 还必须确保将其 Web.config 中的 <httpRuntime targetFramework="..." /> 设置为 ≥4.5.2,否则无论实际的 .NET 版本如何都可能面临漏洞。省略此标签也将导致默认不安全的行为。

为了理解上述表格,ASP.NET 应用程序的 .NET Framework 版本 是应用程序构建时使用的 .NET 版本或 httpRuntime 的 targetFramework (Web.config) 中较低者

此配置标签不应与类似的配置标签混淆:<compilation targetFramework="..." /> 或程序集/项目的 targetFramework,这些标签不足以实现上述表格中所述的默认安全行为。

LINQ to XML

System.Xml.Linq 库中的 XElementXDocument 对象默认情况下都安全,可防止来自外部文件的 XXE 注入和 DoS 攻击。XElement 仅解析 XML 文件中的元素,因此 DTD 完全被忽略。XDocument 默认情况下禁用 XmlResolver 已禁用,因此它免受 SSRF 影响。虽然 DTD 默认情况下 已启用,但从 Framework 4.5.2 及更高版本开始,它不易受到 DoS 攻击,如前所述,但在早期 Framework 版本中可能存在漏洞。有关更多信息,请参阅 Microsoft 关于如何在 .NET 中防止 XXE 和 XML 拒绝服务的指南

XmlDictionaryReader

System.Xml.XmlDictionaryReader 默认是安全的,因为它在尝试解析 DTD 时,编译器会抛出异常,提示“CData 元素在 XML 文档的顶层无效”。如果使用不同的不安全 XML 解析器构造它,它会变得不安全。

XmlDocument

在 .NET Framework 4.5.2 版本之前,System.Xml.XmlDocument 默认是不安全的。XmlDocument 对象内部有一个 XmlResolver 对象,在 4.5.2 版本之前需要将其设置为 null。在 4.5.2 及更高版本中,此 XmlResolver 默认设置为 null。

以下示例展示了如何使其安全:

 static void LoadXML()
 {
   string xxePayload = "<!DOCTYPE doc [<!ENTITY win SYSTEM 'file:///C:/Users/testdata2.txt'>]>"
                     + "<doc>&win;</doc>";
   string xml = "<?xml version='1.0' ?>" + xxePayload;

   XmlDocument xmlDoc = new XmlDocument();
   // Setting this to NULL disables DTDs - Its NOT null by default.
   xmlDoc.XmlResolver = null;
   xmlDoc.LoadXml(xml);
   Console.WriteLine(xmlDoc.InnerText);
   Console.ReadLine();
 }

对于 .NET Framework 版本 ≥4.5.2,这默认是安全的.

如果您使用默认或不安全设置创建自己的非空 XmlResolverXmlDocument 可能会变得不安全。如果您需要启用 DTD 处理,有关如何安全执行此操作的说明在 引用的 MSDN 文章 中有详细描述。

XmlNodeReader

System.Xml.XmlNodeReader 对象默认是安全的,即使使用不安全的解析器构造或包装在其他不安全的解析器中,它们也会忽略 DTD。

XmlReader

System.Xml.XmlReader 对象默认是安全的。

在 .NET Framework 4.0 及更早版本中,它们默认将 ProhibitDtd 属性设置为 false,或者在 .NET 4.0 及更高版本中,将 DtdProcessing 属性设置为 Prohibit。

此外,在 .NET 4.5.2 及更高版本中,属于 XmlReaderXmlReaderSettings 默认将其 XmlResolver 设置为 null,这提供了一层额外的安全保护。

因此,XmlReader 对象仅在 4.5.2 及更高版本中,当 DtdProcessing 属性设置为 Parse 且 XmlReaderSettingXmlResolver 设置为具有默认或不安全设置的非空 XmlResolver 时才会变得不安全。如果您需要启用 DTD 处理,有关如何安全执行此操作的说明在 引用的 MSDN 文章 中有详细描述。

XmlTextReader

在 .NET Framework 4.5.2 版本之前,System.Xml.XmlTextReader 默认是不安全的。以下是如何在各种 .NET 版本中使其安全的方法:

早于 .NET 4.0

在 .NET Framework 4.0 之前的版本中,XmlReader 对象(例如 XmlTextReader)的 DTD 解析行为由 System.Xml.XmlReaderSettingsSystem.Xml.XmlTextReader 类中的布尔型 ProhibitDtd 属性控制。

将这些值设置为 true,可以完全禁用内联 DTD。

XmlTextReader reader = new XmlTextReader(stream);
// NEEDED because the default is FALSE!!
reader.ProhibitDtd = true;  

.NET 4.0 - .NET 4.5.2

在 .NET Framework 4.0 版中,DTD 解析行为已更改。ProhibitDtd 属性已被弃用,取而代之的是新的 DtdProcessing 属性。

但是,他们没有更改默认设置,因此 XmlTextReader 默认仍然容易受到 XXE 攻击。

DtdProcessing 设置为 Prohibit 会导致运行时在 XML 中存在 <!DOCTYPE> 元素时抛出异常。

要自行设置此值,它看起来像这样:

XmlTextReader reader = new XmlTextReader(stream);
// NEEDED because the default is Parse!!
reader.DtdProcessing = DtdProcessing.Prohibit;  

或者,您可以将 DtdProcessing 属性设置为 Ignore,这将不会在遇到 <!DOCTYPE> 元素时抛出异常,而只会简单地跳过它而不处理。最后,如果您确实希望允许和处理内联 DTD,则可以将 DtdProcessing 设置为 Parse

.NET 4.5.2 及更高版本

在 .NET Framework 4.5.2 及更高版本中,XmlTextReader 的内部 XmlResolver 默认设置为 null,这使得 XmlTextReader 默认忽略 DTD。如果您使用默认或不安全设置创建自己的非空 XmlResolverXmlTextReader 可能会变得不安全。

XPathNavigator

System.Xml.XPath.XPathNavigator 在 .NET Framework 4.5.2 之前的版本中默认是不安全的。

这是因为它实现了 IXPathNavigable 对象,例如 XmlDocument,这些对象在 4.5.2 之前的版本中也默认不安全。

您可以通过在 XPathDocument 的构造函数中为其提供一个安全的解析器(例如 XmlReader,它默认是安全的)来使 XPathNavigator 安全。

这是一个例子:

XmlReader reader = XmlReader.Create("example.xml");
XPathDocument doc = new XPathDocument(reader);
XPathNavigator nav = doc.CreateNavigator();
string xml = nav.InnerXml.ToString();

对于 .NET Framework 版本 ≥4.5.2,XPathNavigator 默认是安全的

XslCompiledTransform

System.Xml.Xsl.XslCompiledTransform(一个 XML 转换器)默认是安全的,只要给它的解析器是安全的。

它默认是安全的,因为 Transform() 方法的默认解析器是 XmlReader,而 XmlReader 默认是安全的(如上所述)。

此方法的源代码在此处。

一些 Transform() 方法接受 XmlReaderIXPathNavigable(例如,XmlDocument)作为输入,如果您传入一个不安全的 XML 解析器,那么 Transform 也将是不安全的。

iOS

libxml2

iOS 包含上述 C/C++ libxml2 库,因此如果您直接使用 libxml2,则该指南适用。

然而,直到 iOS6 提供的 libxml2 版本都在 libxml2 2.9 版本之前(2.9 版本默认防范 XXE)。

NSXMLDocument

iOS 还提供了一个 NSXMLDocument 类型,它是基于 libxml2 构建的。

然而,NSXMLDocument 提供了一些 libxml2 中直接不具备的额外 XXE 防护。

根据此页面的“NSXMLDocument 外部实体限制 API”部分:

  • iOS4 及更早版本:所有外部实体默认加载。
  • iOS5 及更高版本:仅加载不需要网络访问的实体。(更安全)

然而,要在任何版本的 iOS 中完全禁用 NSXMLDocument 中的 XXE,您只需在创建 NSXMLDocument 时指定 NSXMLNodeLoadExternalEntitiesNever

PHP

当使用默认 XML 解析器(基于 libxml2)时,PHP 8.0 及更高版本默认阻止 XXE

对于 PHP 8.0 之前的版本,根据 PHP 文档,在使用默认 PHP XML 解析器时,应设置以下内容以防止 XXE:

libxml_set_external_entity_loader(null);

一篇不错的 SensePost 文章介绍了如何在 PHP 中滥用此漏洞,并描述了 Facebook 中已修复的一个基于 PHP 的 XXE 漏洞。

Python

Python 3 官方文档包含关于 xml 漏洞 的章节。截至 2020 年 1 月 1 日,Python 2 不再受支持,但 Python 网站仍包含 一些旧版文档

下表显示了 Python 3 中哪些各种 XML 解析模块容易受到某些 XXE 攻击。

攻击类型 sax etree minidom pulldom xmlrpc
十亿笑攻击 易受攻击 易受攻击 易受攻击 易受攻击 易受攻击
二次膨胀 易受攻击 易受攻击 易受攻击 易受攻击 易受攻击
外部实体扩展 安全 安全 安全 安全 安全
DTD 检索 安全 安全 安全 安全 安全
解压炸弹 安全 安全 安全 安全 易受攻击

为了保护您的应用程序免受适用攻击,存在两个包可帮助您清理输入并保护您的应用程序免受 DDoS 和远程攻击。

Semgrep 规则

Semgrep 是一款用于离线静态分析的命令行工具。使用预构建或自定义规则来强制执行代码和安全标准。

Java

以下是 Java 中不同 XML 解析器的规则:

Digester

识别 org.apache.commons.digester3.Digester 库中的 XXE 漏洞。规则可在此处运行:https://semgrep.dev/s/salecharohit:xxe-Digester

DocumentBuilderFactory

识别 javax.xml.parsers.DocumentBuilderFactory 库中的 XXE 漏洞。规则可在此处运行:https://semgrep.dev/s/salecharohit:xxe-dbf

SAXBuilder

识别 org.jdom2.input.SAXBuilder 库中的 XXE 漏洞。规则可在此处运行:https://semgrep.dev/s/salecharohit:xxe-saxbuilder

SAXParserFactory

识别 javax.xml.parsers.SAXParserFactory 库中的 XXE 漏洞。规则可在此处运行:https://semgrep.dev/s/salecharohit:xxe-SAXParserFactory

SAXReader

识别 org.dom4j.io.SAXReader 库中的 XXE 漏洞。规则可在此处运行:https://semgrep.dev/s/salecharohit:xxe-SAXReader

XMLInputFactory

识别 javax.xml.stream.XMLInputFactory 库中的 XXE 漏洞。规则可在此处运行:https://semgrep.dev/s/salecharohit:xxe-XMLInputFactory

XMLReader

识别 org.xml.sax.XMLReader 库中的 XXE 漏洞。规则可在此处运行:https://semgrep.dev/s/salecharohit:xxe-XMLReader

参考资料