当前位置: 首页 > news >正文

【Java代码审计 | 第十三篇】XXE漏洞成因及防范

未经许可,不得转载。

文章目录

    • XXE
    • 漏洞成因
    • 解析XML的Java方法
      • DocumentBuilder(原生,可回显)
      • SAXReader(DOM4J,第三方库)
      • SAXBuilder(JDOM,第三方库)
      • SAXParserFactory(原生,不可回显)
      • XMLReaderFactory
      • Digester(Apache Commons Digester)
      • 支持XInclude的DocumentBuilder
      • SAXParserFactory与XMLReader结合
    • 漏洞代码
    • 防范

在这里插入图片描述

XXE

XXE(XML External Entity,XML外部实体注入) 是一种安全漏洞,攻击者通过利用XML解析器处理外部实体的功能,读取本地文件、发起网络请求或导致拒绝服务攻击。

XXE的常见攻击场景:
1、读取本地文件:通过加载外部实体,读取服务器上的敏感文件(如/etc/passwd)。
2、发起SSRF攻击:通过外部实体发起网络请求,访问内网服务或云服务元数据。
3、拒绝服务攻击:通过构造恶意的XML实体,消耗服务器资源(如“Billion Laughs”攻击)。

漏洞成因

XXE通常发生在应用程序解析用户提供的XML输入时,未禁用外部实体解析的情况下。

解析XML的Java方法

Java中解析XML的方法有多种,常见的有以下四种:DOM、DOM4J、JDOM 和 SAX。每种方法各有特点,适用于不同的场景。

DocumentBuilder(原生,可回显)

import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.DocumentBuilder;
import org.w3c.dom.Document;
import java.io.StringReader;
import org.xml.sax.InputSource;

DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
DocumentBuilder db = dbf.newDocumentBuilder();
StringReader sr = new StringReader(xml_con); // xml_con为XML字符串
InputSource is = new InputSource(sr);
Document document = db.parse(is); // 解析XML并返回Document对象

特点:

  • 基于DOM模型,将整个XML文档加载到内存中,生成一棵DOM树。
  • 可回显:解析后的内容可以通过Document对象进行操作和访问。
  • 适用于需要频繁访问和修改XML内容的场景。

风险:如果未禁用外部实体解析,可能导致XXE漏洞。

SAXReader(DOM4J,第三方库)

import org.dom4j.io.SAXReader;
import org.dom4j.Document;
import javax.servlet.http.HttpServletRequest;

SAXReader saxReader = new SAXReader();
Document document = saxReader.read(request.getInputStream()); // 从请求流中读取并解析XML

特点:

  • 基于DOM4J库,提供更简洁的API。
  • 可回显:解析后的内容可以通过Document对象进行操作和访问。
  • 适用于需要灵活处理XML的场景。

风险:默认情况下支持外部实体解析,需显式禁用以防止XXE漏洞。

SAXBuilder(JDOM,第三方库)

import org.jdom2.input.SAXBuilder;
import org.jdom2.Document;
import javax.servlet.http.HttpServletRequest;

SAXBuilder builder = new SAXBuilder();  
Document document = builder.build(request.getInputStream()); // 从请求流中读取并解析XML

特点:

  • 基于JDOM库,提供更直观的API。
  • 可回显:解析后的内容可以通过Document对象进行操作和访问。
  • 适用于需要快速解析和操作XML的场景。

风险:默认情况下支持外部实体解析,需显式禁用以防止XXE漏洞。

SAXParserFactory(原生,不可回显)

import javax.xml.parsers.SAXParserFactory;
import javax.xml.parsers.SAXParser;
import org.xml.sax.helpers.DefaultHandler;
import javax.servlet.http.HttpServletRequest;

SAXParserFactory factory = SAXParserFactory.newInstance(); 
SAXParser saxParser = factory.newSAXParser();
DefaultHandler handler = new DefaultHandler(); // 自定义处理器
saxParser.parse(request.getInputStream(), handler); // 解析XML并触发处理器事件

特点:

  • 基于SAX模型,采用事件驱动的方式解析XML。
  • 不可回显:解析过程中通过事件回调处理数据,不生成完整的DOM树。
  • 适用于处理大型XML文件或流式数据。

风险:默认情况下支持外部实体解析,需显式禁用以防止XXE漏洞。

其他解析方法如下。

XMLReaderFactory

import org.xml.sax.XMLReader;
import org.xml.sax.helpers.XMLReaderFactory;
import org.xml.sax.InputSource;
import java.io.StringReader;

XMLReader xmlReader = XMLReaderFactory.createXMLReader();
xmlReader.parse(new InputSource(new StringReader(xml_con))); // 解析XML字符串

特点:

  • 基于SAX模型,提供更底层的API。

  • 不可回显:通过事件回调处理数据。

  • 适用于需要自定义解析逻辑的场景。

Digester(Apache Commons Digester)

import org.apache.commons.digester3.Digester;
import java.io.StringReader;

Digester digester = new Digester();
digester.parse(new StringReader(xml_con)); // 解析XML字符串

特点:

  • 基于规则驱动的解析方式,适合将XML映射为Java对象。

  • 不可回显:解析过程中直接生成Java对象。

  • 适用于配置文件解析或数据绑定场景。

支持XInclude的DocumentBuilder

import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.DocumentBuilder;
import org.w3c.dom.Document;
import java.io.StringReader;
import org.xml.sax.InputSource;

DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
dbf.setXIncludeAware(true);   // 支持XInclude
dbf.setNamespaceAware(true);  // 支持命名空间
DocumentBuilder db = dbf.newDocumentBuilder();
StringReader sr = new StringReader(xml_con);
InputSource is = new InputSource(sr);
Document document = db.parse(is);  // 解析XML

特点:

  • 支持XInclude和命名空间,适合处理复杂的XML文档。

  • 可回显:解析后的内容可以通过Document对象进行操作和访问。

  • 适用于需要高级XML特性的场景。

SAXParserFactory与XMLReader结合

import javax.xml.parsers.SAXParserFactory;
import javax.xml.parsers.SAXParser;
import org.xml.sax.XMLReader;
import org.xml.sax.InputSource;
import java.io.StringReader;

SAXParserFactory spf = SAXParserFactory.newInstance();
SAXParser saxParser = spf.newSAXParser();
XMLReader xmlReader = saxParser.getXMLReader();
xmlReader.parse(new InputSource(new StringReader(xml_con))); // 解析XML字符串

特点:

  • 结合SAXParserFactory和XMLReader,提供更灵活的解析方式。
  • 不可回显:通过事件回调处理数据。
  • 适用于需要自定义解析逻辑的场景。

漏洞代码

以下漏洞代码未禁用外部实体解析:

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

public class VulnerableXXE {
    public static void main(String[] args) {
        HttpServletRequest request = getRequest();
        // 从 GET 请求中获取 XML 内容
        String xml = request.getParameter("xml");
        
        if (xml == null || xml.isEmpty()) {
            System.out.println("请提供 XML 内容作为参数");
            return;
        }
        
        try {
            // 创建 DocumentBuilderFactory 对象
            DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
            // 未禁用对外部实体的支持,导致 XXE 漏洞
            DocumentBuilder builder = factory.newDocumentBuilder();

            // 解析用户传递的 XML 内容
            Document document = builder.parse(new ByteArrayInputStream(xml.getBytes()));

            // 输出解析结果
            System.out.println("解析结果:");
            System.out.println(document.getDocumentElement().getTextContent());
        } catch (Exception e) {
            System.err.println("解析 XML 时发生错误:");
            e.printStackTrace();
        }
    }
}

以上未禁用外部实体解析,攻击者可以通过<!ENTITY>标签加载外部文件(如file:///etc/passwd)。

<!ENTITY> 是 XML 中的一个声明,用于定义 实体。在 XML 中,实体可以用于以下目的:引用字符或者字符串;引用外部资源,例如文件或 URL;扩展某些 XML 元素或属性的内容。

payload:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE foo [ <!ENTITY xxe SYSTEM "file:///etc/passwd"> ]>
<foo>&xxe;</foo>

防范

禁用外部实体解析、对用户提供的XML输入进行严格的验证、选择默认禁用外部实体解析的库,或在初始化时显式禁用。

例如在使用DocumentBuilderFactory、SAXParserFactory等原生方法时,显式禁用外部实体解析:

factory.setFeature("http://xml.org/sax/features/external-general-entities", false);
factory.setFeature("http://xml.org/sax/features/external-parameter-entities", false);

相关文章:

  • 数据结构第六节:AVL树(初阶)
  • API调试工具的无解困境:白名单、动态IP与平台设计问题
  • STM32基础教程——对射式红外传感器计数实验
  • java读取Markdown配置文件
  • 【2025前端高频面试题——系列二之vue生命周期:vue2/vue3】
  • 【量化交易笔记】15.因子的来源和生成
  • FX-C++结构体与类的区别
  • 英语-新概念-第三册
  • 基于PyTorch的深度学习3——非标量反向传播
  • 轻量级TCC框架的实现
  • c++中的数学函数库(少)
  • 基于策略模式的智能提示语生成器设计与实现——以Tkinter GUI开发为例
  • 软考 中级软件设计师 考点知识点笔记总结 day02
  • AI赋能零代码编程基石:Anaconda全栈环境搭建与避坑指南
  • Golang | Gin(简洁版)
  • 深入Flink运行时架构:JobManager与TaskManager协作全解析
  • numpy常用函数详解
  • vulnhub靶场之【digitalworld.local系列】的FALL靶机
  • Java中,BIO、NIO和AIO三种模型的区别和适用场景
  • scala类型检测和转换
  • 做网站需要每年都交钱吗/怎么做网页设计的页面
  • 企业首次建设网站的策划方案/竞价如何屏蔽恶意点击
  • 工程建设国家标准网站/排名优化公司电话
  • 做网站被用作非法用途/网站优化排名公司哪家好
  • 北京好用的h5建站/app拉新推广平台渠道商
  • 怎么可以上传自己做的网站/必应搜索引擎网址