如何防止 XXE 攻击

2022-01-10 00:00:00 xml xml-parsing transform java

我们对代码进行了安全审计,其中提到我们的代码容易受到 XML 外部实体 (XXE) 攻击.

We had a security audit on our code, and it mentioned that our code is vulnerable to XML EXternal Entity (XXE) attacks.

XML 外部实体攻击受益于在处理时动态构建文档的 XML 特性.一个 XMLentity 允许动态地包含来自给定资源的数据.外部实体允许 XML 文档包含数据来自外部 URI.除非另外配置,否则外部实体会强制 XML 解析器访问指定的资源通过 URI,例如,本地计算机或远程系统上的文件.此行为将应用程序暴露给 XML External实体 (XXE) 攻击,可用于执行本地系统的拒绝服务,获得对文件的未经授权的访问本地机器,扫描远程机器,并对远程系统执行拒绝服务.

Explanation

XML External Entities attacks benefit from an XML feature to build documents dynamically at the time of processing. An XML entity allows inclusion of data dynamically from a given resource. External entities allow an XML document to include data from an external URI. Unless configured to do otherwise, external entities force the XML parser to access the resource specified by the URI, e.g., a file on the local machine or on a remote system. This behavior exposes the application to XML External Entity (XXE) attacks, which can be used to perform denial of service of the local system, gain unauthorized access to files on the local machine, scan remote machines, and perform denial of service of remote systems.

以下 XML 文档显示了 XXE 攻击的示例.

The following XML document shows an example of an XXE attack.

<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE foo [
<!ELEMENT foo ANY >
<!ENTITY xxe SYSTEM "file:///dev/random" >]><foo>&xxe;</foo>

如果 XML 解析器尝试将实体替换为/dev/random 文件.

This example could crash the server (on a UNIX system), if the XML parser attempts to substitute the entity with the contents of the /dev/random file.

应该安全地配置 XML 解组器,以使其不允许外部实体作为传入 XML 的一部分文件.

The XML unmarshaller should be configured securely so that it does not allow external entities as part of an incoming XML document.

为避免 XXE 注入,请勿使用将 XML 源直接处理为 java.io.Filejava.io.Readerjava.io.InputStream.使用安全配置的解析器解析文档,并使用将安全解析器作为 XML 源的解组方法,如下例所示:

To avoid XXE injection do not use unmarshal methods that process an XML source directly as java.io.File, java.io.Reader or java.io.InputStream. Parse the document with a securely configured parser and use an unmarshal method that takes the secure parser as the XML source as shown in the following example:

DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
dbf.setExpandEntityReferences(false);
DocumentBuilder db = dbf.newDocumentBuilder();
Document document = db.parse(<XML Source>);
Model model = (Model) u.unmarshal(document);

以下代码是审计发现 XXE 攻击的地方:

The code below is where the audit found the XXE attack:

Transformer transformer = TransformerFactory.newInstance().newTransformer();
transformer.setOutputProperty(OutputKeys.INDENT, "yes");
System.out.println("outputing to : " + outputLocation);
File outputFile = new File(outputLocation);
StreamResult result = new StreamResult(outputFile);
DOMSource source = new DOMSource(doc);
transformer.transform(source, result);

如何在我的代码中实施上述建议?我在哪里漏掉了东西?

How can I implement the above recommendation in my code? Where am I missing things?

推荐答案

您可以使用与 DocumentBuilderFactory 相同的方法:

You can use the same approach with DocumentBuilderFactory:

DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
factory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);
...

要让每个人都自动使用它,您需要创建自己的实现(通过扩展您当前使用的实现;使用您的调试器来找出答案).在构造函数中设置特征.

To make everyone use this automatically, you need to create your own implementation (by extending the one which you're currenly using; use your debugger to find out). Set the feature in the constructor.

然后你可以将System属性javax.xml.parsers.DocumentBuilderFactory中的新工厂使用到Java VM,每个人都会使用它.

Then you can pass the new factory to use in the System property javax.xml.parsers.DocumentBuilderFactory to the Java VM and everyone will use it.

相关文章