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_NOENT
和 XML_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¶
DocumentBuilderFactory
、SAXParserFactory
和 DOM4J
XML
解析器可以使用相同的技术抵御 XXE 攻击。
为简洁起见,我们仅演示如何保护 DocumentBuilderFactory
解析器。保护此解析器的附加说明嵌入在示例代码中:
JAXP DocumentBuilderFactory
的 setFeature 方法允许开发人员控制启用或禁用哪些特定于实现的 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();
- 通过将 此功能 设置为
true
,禁止内联 DTD。 - 通过将 此功能 设置为
false
,不包含外部实体。 - 通过将 此功能 设置为
false
,不包含参数实体。 - 通过将 此功能 设置为
false
,不包含外部 DTD。
注意:上述防御措施需要 Java 7 update 67、Java 8 update 20 或更高版本,因为根据 CVE-2014-6517,DocumentBuilderFactory
和 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.Unmarshaller
的 unmarshal
函数的源是使用具有安全属性(即 XMLInputFactory.SUPPORT_DTD
和 XMLInputFactory.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);
请注意,createXMLStreamReader
和 unmarshal
方法都有多个带不同源类型的重载,因此您需要选择正确的重载并进行可能的转换。
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 OXM 和 Spring MVC 中发现了一些 XXE 漏洞。以下版本的 Spring Framework 容易受到 XXE 攻击:
- 3.0.0 到 3.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。 - 对于
StAXSource
,XMLStreamReader
已由用户代码创建,该代码负责防范 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
库中的 XElement
和 XDocument
对象默认情况下都安全,可防止来自外部文件的 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,这默认是安全的.
如果您使用默认或不安全设置创建自己的非空 XmlResolver
,XmlDocument
可能会变得不安全。如果您需要启用 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 及更高版本中,属于 XmlReader
的 XmlReaderSettings
默认将其 XmlResolver
设置为 null,这提供了一层额外的安全保护。
因此,XmlReader
对象仅在 4.5.2 及更高版本中,当 DtdProcessing
属性设置为 Parse 且 XmlReaderSetting
的 XmlResolver
设置为具有默认或不安全设置的非空 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.XmlReaderSettings
和 System.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。如果您使用默认或不安全设置创建自己的非空 XmlResolver
,XmlTextReader
可能会变得不安全。
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()
方法接受 XmlReader
或 IXPathNavigable
(例如,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