XML外部实体注入(XXE)
XML外部实体注入(XML eXternal Entity Injection,XXE)是一种针对解析XML输入的应用程序的攻击。当应用程序处理包含不受信任的外部实体引用的XML输入,并使用配置不当的XML解析器时,就可能发生这种攻击。此类攻击可能导致机密数据泄露、拒绝服务攻击(DoS)、服务器端请求伪造(SSRF)以及从解析器所在服务器进行端口扫描等一系列系统安全问题。
XXE攻击的危害
- 机密数据泄露:攻击者可以利用XXE攻击读取系统中的机密文件或数据。
- 拒绝服务攻击(DoS):攻击者可以构造恶意的XML文档,导致解析器陷入无限循环或消耗大量资源,从而造成拒绝服务。
- 服务器端请求伪造(SSRF):攻击者可以利用XXE攻击,让服务器发送请求到任意地址,执行端口扫描或访问内部系统。
- 其他系统影响:包括但不限于代码执行、数据篡改和权限提升。
防止XXE攻击的有效措施
除了通用的输入验证,还可以采用以下方式有效防止XXE攻击:
- 禁用XML外部实体和DTD处理:在应用程序的所有XML解析器中禁用XML外部实体和DTD处理。
- 实施基于“白名单”的服务器端输入验证:过滤或清理XML文档、头信息或节点中的恶意数据。
- 验证XML或XSL文件上传功能:使用XSD验证或类似方法对输入进行验证。
- 及时打补丁或升级XML处理器和库:使用依赖项检查工具,确保使用最新版本的处理器和库,并将SOAP更新到SOAP 1.2或更高版本。
Java中的防范措施示例
防止XXE的最安全方法是完全禁用DTD(外部实体)。根据不同的解析器,方法如下:
1. SAXBuilder
SAXBuilder builder = new SAXBuilder(true);
Document doc = builder.build(new InputSource());
或者:
SAXBuilder builder = new SAXBuilder();
builder.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
builder.setFeature("http://xml.org/sax/features/external-general-entities", false);
builder.setFeature("http://xml.org/sax/features/external-parameter-entities", false);
builder.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false);
Document doc = builder.build(new InputSource());
2. SAXReader
SAXReader saxReader = new SAXReader();
saxReader.setFeature("http://apache.org/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);
saxReader.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false);
saxReader.read(new InputSource());
3. SAXTransformerFactory
SAXTransformerFactory sf = (SAXTransformerFactory) SAXTransformerFactory.newInstance();
sf.setAttribute(XMLConstants.ACCESS_EXTERNAL_DTD, "");
sf.setAttribute(XMLConstants.ACCESS_EXTERNAL_STYLESHEET, "");
StreamSource source = new StreamSource(new InputSource());
sf.newTransformerHandler(source);
4. SchemaFactory
SchemaFactory factory = SchemaFactory.newInstance("http://www.w3.org/2001/XMLSchema");
factory.setProperty(XMLConstants.ACCESS_EXTERNAL_DTD, "");
factory.setProperty(XMLConstants.ACCESS_EXTERNAL_SCHEMA, "");
StreamSource source = new StreamSource(new InputSource());
Schema schema = factory.newSchema(source);
5. TransformerFactory
TransformerFactory tf = TransformerFactory.newInstance();
tf.setAttribute(XMLConstants.ACCESS_EXTERNAL_DTD, "");
tf.setAttribute(XMLConstants.ACCESS_EXTERNAL_STYLESHEET, "");
StreamSource source = new StreamSource(new InputSource());
tf.newTransformer().transform(source, new DOMResult());
6. ValidatorSample
SchemaFactory factory = SchemaFactory.newInstance("http://www.w3.org/2001/XMLSchema");
Schema schema = factory.newSchema();
Validator validator = schema.newValidator();
validator.setProperty(XMLConstants.ACCESS_EXTERNAL_DTD, "");
validator.setProperty(XMLConstants.ACCESS_EXTERNAL_SCHEMA, "");
StreamSource source = new StreamSource(new InputSource());
validator.validate(source);
7. XMLReader
XMLReader reader = XMLReaderFactory.createXMLReader();
reader.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
reader.setFeature("http://apache.org/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);
reader.parse(new InputSource(new InputSource()));
.Net中的防范措施示例
1. LINQ to XML
在默认情况下,System.Xml.Linq库中的XElement和XDocument对象不会受到XXE注入攻击,但会受到DoS攻击。为了在不同攻击类型之间提供安全保障,请参考微软关于如何防止.NET中的XXE和XML拒绝服务攻击的指南。
2. XmlDictionaryReader
System.Xml.XmlDictionaryReader在默认情况下是安全的,因为当它试图解析DTD时,编译器会抛出一个异常。但是,如果使用不同的不安全XML解析器构造,它会变得不安全。
3. XmlDocument
在.NET Framework 4.5.2版本之前,System.Xml.XmlDocument在默认情况下是不安全的。以下是确保其安全的示例:
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();
// 设置为NULL以禁用DTD - 默认情况下不是NULL
xmlDoc.XmlResolver = null;
xmlDoc.LoadXml(xml);
Console.WriteLine(xmlDoc.InnerText);
Console.ReadLine();
}
在4.5.2及以上版本中,XmlDocument的XmlResolver默认设置为空。
4. XmlNodeReader
System.Xml.XmlNodeReader对象在默认情况下是安全的,即使使用不安全的解析器构造或包装在另一个不安全的解析器中也会忽略DTD。
5. XmlReader
System.Xml.XmlReader对象在默认情况下是安全的。在.NET版本4.5.2及以后,XmlReaderSettings的XmlResolver默认设置为null,提供了额外的安全保障。
6. XmlTextReader
在.NET Framework 4.5.2版本之前,XmlTextReader默认情况下是不安全的。以下是不同版本中的安全设置方法:
a) .NET 4.0之前
XmlTextReader reader = new XmlTextReader(stream);
// 需要设置为TRUE,因为默认是FALSE
reader.ProhibitDtd = true;
b) .NET 4.0 - .NET 4.5.2
XmlTextReader reader = new XmlTextReader(stream);
// 需要设置为Prohibit,因为默认是Parse
reader.DtdProcessing = DtdProcessing.Prohibit;
c) .NET 4.5.2及以上
在4.5.2及以上版本中,XmlTextReader的XmlResolver默认设置为空。如果创建自己的非空XmlResolver并使用默认设置或不安全设置,则会变得不安全。
参考链接
- OWASP XXE Prevention Cheat Sheet:https://cheatsheetseries.owasp.org/cheatsheets/XML_External_Entity_Prevention_Cheat_Sheet.html
- Microsoft .NET Framework Security Guidelines:https://docs.microsoft.com/en-us/dotnet/standard/security/
- Java Secure Coding Guidelines:https://www.oracle.com/java/technologies/javase/seccodeguide.html