如何禁用XXE处理?

如何禁用XXE处理?

在我的上一篇文章中,我谈到了在目前流行的开源项目中发现的XXE漏洞,以及如何更全面地评估该类问题。今天我将讨论禁用XXE处理的几种策略。
外部实体(XXE)和内部实体对于构建简洁的XML文档非常重要。防止出现XXE漏洞的适当办法取决于您的项目需要。它可以像完全禁用外部实体一样简单,也可以只对您需要的实体和信任的实体进行稍微复杂一点的处理就可以有效解决。
与任何其他被研究的语言相比,Java语言,尤其是JAXP API,为我们提供了更多的选项,所以我们的代码示例和解决方案将主要使用Java语言来进行,但我们也展示了其他语言与Java语言具有同等效果的解决方案。

禁用DOCTYPE

如上文所述,实体是在XML文档的DOCTYPE中声明的,因此当项目中不需要DOCTYPE声明时,简单而安全的解决方案是完全禁用该类实体。
当设置为true时,disallow doctype decl功能指示XML处理器在遇到doctype声明时引发异常:
factory.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);

禁用外部实体声明

一种不太常规化的解决方案是允许DOCTYPE声明,而只禁止外部实体声明。因此,如果找到外部实体,XML处理器会引发异常,但会正常处理其他DTD声明。通过将以下两个功能都设置为false,可以禁用参数和常规外部实体:
factory.setFeature("http://xml.org/sax/features/external-general-entities", false);factory.setFeature("http://xml.org/sax/features/external-parameter-entities", false);
PHP的libxml库在默认情况下是安全的,因为外部实体被禁用,除非LIBXML_NOENT参数显式设置为允许状态:
$doc = simplexml_load_string($xml, "SimpleXMLElement", LIBXML_NOENT); // !XXE enabled!$doc = simplexml_load_string($xml, "SimpleXMLElement"); // XXE disabled
注:LIBXML_NOENT参数名称具有误导性,因为它不会在DOM树中创建实体引用节点来解释“NOENT”后缀,而是用该参数的内容对实体进行替换。

启用安全处理

可以按如下方式显示启用 Java JAXP 安全处理功能 (FSP):
factory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);
该功能通过应用限制来安全配置XML处理器的中央Java机制,以防止存在XML拒绝服务攻击和XXE漏洞等潜在风险。
在默认情况下,FSP部分启用,可防止XML拒绝服务攻击。然而,只有当通过调用setFeature方法将FSP属性设置为true并显示完全启用FSP时,外部连接才会被禁止。但实际情况下,并非所有的XML处理器均如此操作,例如在Apache Xerces上,FSP不限制外部连接,因此无法防止XXE漏洞。
因此,请务必测试有关XXE漏洞的FSP行为,并使用其他属性(例如我们在本文中介绍的其他属性)来明确禁用或限制XXE。

禁用实体引用扩展

对于每个实体引用(&entityname;)可以在XML文档中找到,DOM XML解析器可以用其值替换引用,也可以在DOM树中创建一个“empty”实体引用节点,具体选择取决于配置情况。利用实体引用的值替换实体引用的机制,也被称之为“扩展实体引用”,在解析恶意构建的XML文件时,可能会泄露敏感信息,这点与我们在本系列的第一篇文章中讨论的内容一致。
在 Java 中,DocumentBuilder 工厂的 setExpandEntityReferences 方法用于配置实体引用方式:
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();factory.setExpandEntityReferences(false);
当使用false调用时,不会扩展实体引用,从而能够有效防止XXE漏洞。
需要重点强调的一点是,OpenJDK13之前版本提供的Xerces处理器不支持将expandEntityReferences属性设置为false;所以需要扩展实体引用。实际上最好的办法是对OpenJDK进行升级,但如果未对其进行升级,规则S2755能够检测到它们。
C/C++ Xerces库的等效功能是:
xercesc::XercesDOMParser *DOMparser = new xercesc::XercesDOMParser();DOMparser->setCreateEntityReferenceNodes(true);

创建实体引用节点意味着实体引用不会被扩展,因此不会导致外部内容泄露。但要实现正确设置可能存在很多困难,因为这些方法名称不属于那种清晰易懂的类型,因而很容易发生概念混淆。例如,我们最近为改进OWASP C++指南做出了很多努力。之前的情况曾错误地建议将此参数设置为“false”而非“true”。

因此,如果您仍然依赖之前的OWASP建议,将激活C++规则S2755。例如,msix-packaging微软开源项目就是一个用于打包和解压MSIX包的C++工具:

扩展(或不扩展)外部实体引用这一步骤是在已获取外部内容之后进行的。因此,即使扩展被禁用并且攻击者无法窃取数据,仍然会执行对外部资源的请求。这种情况存在着安全风险,但该类风险可被视为很低,因为攻击者只能进行“盲目的SSRF”攻击。如果您认为此观点不可接受,那么您需要对上文讨论的任一解决方案进行考虑。
注:在假设XML处理器可以访问此API(https://internal.network/private/username/admin)的情况下,当攻击者欺骗服务器(在本例中为XML处理器)执行任意请求而无法检索响应内容时,就会发生盲目的SSRF。
继而攻击者可以对该API端点执行请求。在该案例的最差情况下,攻击者可能够窃取用户名信息,具体情况取决于XML处理器的错误处理程度。

结语

在本篇文章中,我们知道了如何配置您的XML解析器从而有效防止XXE漏洞,从禁用XXE声明(如果您根本不需要这类声明)到禁用引用扩展(如果您需要并希望取得XXE声明但不允许用其替换时),有时您的项目可能需要更灵活和更精确的修复来对特定XXE解析进行控制和设定限制,这些XXE分析是您所期望的并且是安全的。这是我们将在第三篇也是最后一篇文章中见到的内容。

作者简介:

ERIC THEROND
安全研究人员 

文章来源:https://blog.sonarsource.com/secure-xml-processor

发表评论

您的电子邮箱地址不会被公开。 必填项已用*标注