在我的上一篇文章中,我谈到了在目前盛行的开源项目中创造的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
安全研究职员