写点什么

如何禁用 XXE 处理?

  • 2022 年 4 月 11 日
  • 本文字数:2231 字

    阅读完需:约 7 分钟

如何禁用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 分析是您所期望的并且是安全的。这是我们将在第三篇也是最后一篇文章中见到的内容。

用户头像

还未添加个人签名 2021.05.18 加入

还未添加个人简介

评论

发布
暂无评论
如何禁用XXE处理?_漏洞扫描_龙智—DevSecOps解决方案_InfoQ写作平台