如何防止XXE攻击

2022-09-01 05:12:19

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

解释

XML 外部实体攻击受益于在处理时动态生成文档的 XML 功能。XML 实体允许动态包含来自给定资源的数据。外部实体允许 XML 文档包含来自外部 URI 的数据。除非配置为不这样做,否则外部实体会强制 XML 解析器访问由 URI 指定的资源,例如,本地计算机或远程系统上的文件。此行为使应用程序暴露于 XML 外部实体 (XXE) 攻击,这些攻击可用于执行本地系统的拒绝服务、获取对本地计算机上文件的未经授权的访问、扫描远程计算机以及执行远程系统的拒绝服务。

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

<?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 文件的内容替换实体,则此示例可能会使服务器崩溃(在 UNIX 系统上)。

建议

应安全地配置 XML 取消编组程序,使其不允许外部实体作为传入 XML 文档的一部分。

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

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

下面的代码是审核发现XXE攻击的地方:

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);

如何在我的代码中实现上述建议?我在哪里错过了什么?


答案 1

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

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

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

然后,您可以将要在 System 属性中使用的新工厂传递给 Java VM,每个人都会使用它。javax.xml.parsers.DocumentBuilderFactory


答案 2

请注意,单独使用FEATURE_SECURE_PROCESSING似乎不够安全(来自blackhat-pdf):

...尽管Oracle建议XML解析器在启用FEATURE _SECURE_PROCESSING时实际上并没有限制外部连接。

OWASP 建议ACCESS_EXTERNAL_DTD和ACCESS_EXTERNAL_STYLESHEET。

总之,这将使:

TransformerFactory trfactory = TransformerFactory.newInstance();
trfactory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);
trfactory.setAttribute(XMLConstants.ACCESS_EXTERNAL_DTD, "");
trfactory.setAttribute(XMLConstants.ACCESS_EXTERNAL_STYLESHEET, "");

实际上,这个问题是以下问题的副本:如何防止TransformerFactory上的XML外部实体注入


推荐