Java XXE 防护实战:常见漏洞场景与防御代码全收录

Java XXE 防护实战:常见漏洞场景与防御代码全收录

🛡️ Java XXE 防护示例与详解

本文件涵盖常见 Java XML 解析器的 XXE 安全配置方法,适用学习和辅助判断审计目标是否存在XXE问题:

  • 💥 默认行为
  • ⚠️ 潜在风险
  • 防护方式
  • 👨‍💻 防护代码

📘 1. DocumentBuilderFactory

💥 默认行为:

允许 DTD、实体引用,容易触发 XXE 注入。

⚠️ 潜在风险:

攻击者可构造外部实体,引发敏感信息读取、SSRF、DoS 等攻击。

✅ 防护方式:

通过 setFeature() 禁用 DTD 和实体加载。

👨‍💻 防护代码:

 import javax.xml.parsers.DocumentBuilderFactory;
 import org.w3c.dom.Document;
 ​
 public class SafeDOMParser {
     public static void main(String[] args) throws Exception {
         DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
         factory.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
         factory.setFeature("http://xml.org/sax/features/external-general-entities", false);
         factory.setFeature("http://xml.org/sax/features/external-parameter-entities", false);
 ​
         Document doc = factory.newDocumentBuilder().parse(new java.io.ByteArrayInputStream("<xml></xml>".getBytes()));
     }
 }

📘 2. SAXParserFactory

💥 默认行为:

和 DOM 类似,也允许实体展开。

⚠️ 潜在风险:

构造 DTD 搭配实体即可引发漏洞。

✅ 防护方式:

通过 setFeature() 禁用危险功能。

👨‍💻 防护代码:

 import javax.xml.parsers.SAXParserFactory;
 import org.xml.sax.helpers.DefaultHandler;
 ​
 public class SafeSAXParser {
     public static void main(String[] args) throws Exception {
         SAXParserFactory factory = SAXParserFactory.newInstance();
         factory.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
         factory.setFeature("http://xml.org/sax/features/external-general-entities", false);
         factory.setFeature("http://xml.org/sax/features/external-parameter-entities", false);
 ​
         factory.newSAXParser().parse(new java.io.ByteArrayInputStream("<xml/>".getBytes()), new DefaultHandler());
     }
 }

📘 3. XMLReader

💥 默认行为:

不设置安全特性即有漏洞风险。

⚠️ 潜在风险:

使用不安全 XMLReader 导致的实体解析。

✅ 防护方式:

直接设置 SAX feature。

👨‍💻 防护代码:

 import org.xml.sax.XMLReader;
 import org.xml.sax.helpers.XMLReaderFactory;
 import org.xml.sax.helpers.DefaultHandler;
 ​
 public class SafeXMLReader {
     public static void main(String[] args) throws Exception {
         XMLReader reader = XMLReaderFactory.createXMLReader();
         reader.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
         reader.setFeature("http://xml.org/sax/features/external-general-entities", false);
         reader.setFeature("http://xml.org/sax/features/external-parameter-entities", false);
 ​
         reader.setContentHandler(new DefaultHandler());
         reader.parse(new org.xml.sax.InputSource(new java.io.StringReader("<xml/>")));
     }
 }

📘 4. XMLInputFactory(StAX)

💥 默认行为:

开启 DTD 和实体引用。

⚠️ 潜在风险:

即便没有 DTD,也可能加载实体。

✅ 防护方式:

通过 setProperty() 禁用 DTD、实体支持。

👨‍💻 防护代码:

 import javax.xml.stream.*;
 ​
 public class SafeStAX {
     public static void main(String[] args) throws Exception {
         XMLInputFactory factory = XMLInputFactory.newInstance();
         factory.setProperty(XMLInputFactory.SUPPORT_DTD, false);
         factory.setProperty(XMLInputFactory.IS_SUPPORTING_EXTERNAL_ENTITIES, false);
 ​
         XMLStreamReader reader = factory.createXMLStreamReader(new java.io.StringReader("<xml></xml>"));
         while (reader.hasNext()) {
             reader.next();
         }
     }
 }

📘 5. SAXReader(dom4j)

💥 默认行为:

内部创建未配置的 XMLReader。

⚠️ 潜在风险:

默认使用不安全 reader,容易产生 XXE。

✅ 防护方式:

显式创建并配置 XMLReader,然后传入构造器。

👨‍💻 防护代码:

 import org.dom4j.io.SAXReader;
 import org.xml.sax.XMLReader;
 import org.xml.sax.helpers.XMLReaderFactory;
 ​
 public class SafeSAXReader {
     public static void main(String[] args) throws Exception {
         XMLReader xmlReader = XMLReaderFactory.createXMLReader();
         xmlReader.setFeature("http://xml.org/sax/features/external-general-entities", false);
         xmlReader.setFeature("http://xml.org/sax/features/external-parameter-entities", false);
         xmlReader.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
 ​
         SAXReader reader = new SAXReader(xmlReader);
         org.dom4j.Document doc = reader.read(new java.io.StringReader("<xml/>"));
     }
 }

📘 6. SAXBuilder(JDOM)

💥 默认行为:

若不指定 XMLReader,也使用不安全解析器。

⚠️ 潜在风险:

默认构造器调用未加固 parser。

✅ 防护方式:

传入经过配置的 XMLReader 实例。

👨‍💻 防护代码:

 import org.jdom2.input.SAXBuilder;
 import javax.xml.parsers.SAXParserFactory;
 import org.xml.sax.XMLReader;
 ​
 public class SafeSAXBuilder {
     public static void main(String[] args) throws Exception {
         SAXParserFactory factory = SAXParserFactory.newInstance();
         factory.setFeature("http://xml.org/sax/features/external-general-entities", false);
         factory.setFeature("http://xml.org/sax/features/external-parameter-entities", false);
         factory.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
 ​
         XMLReader xmlReader = factory.newSAXParser().getXMLReader();
         SAXBuilder builder = new SAXBuilder(xmlReader);
         org.jdom2.Document doc = builder.build(new java.io.StringReader("<xml/>"));
     }
 }

📘 7. XStream

💥 默认行为(旧版):

可读取任意类型、支持外部实体。

⚠️ 潜在风险:

反序列化任意对象、文件读取。

✅ 防护方式:

  • 使用 DomDriver
  • 限制允许类型。

👨‍💻 防护代码:

 import com.thoughtworks.xstream.XStream;
 import com.thoughtworks.xstream.io.xml.DomDriver;
 ​
 public class SafeXStream {
     public static void main(String[] args) {
         XStream xstream = new XStream(new DomDriver());
         xstream.allowTypes(new Class[]{MyBean.class});
 ​
         MyBean obj = new MyBean("hello");
         String xml = xstream.toXML(obj);
         System.out.println(xml);
     }
 ​
     static class MyBean {
         private String name;
         public MyBean(String name) { this.name = name; }
     }
 }

📘 8. JAXB(结合安全 DOM)

💥 默认行为:

若不指定安全 parser,底层仍可能存在 XXE。

⚠️ 潜在风险:

依赖默认 factory 引发漏洞。

✅ 防护方式:

配合 DOMFactory 设置特性后再解析。

👨‍💻 防护代码:

 import javax.xml.parsers.DocumentBuilderFactory;
 import javax.xml.bind.*;
 import org.w3c.dom.Document;
 ​
 public class SafeJAXB {
     public static void main(String[] args) 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);
 ​
         Document doc = dbf.newDocumentBuilder().parse(new java.io.ByteArrayInputStream("<user><name>xx</name></user>".getBytes()));
 ​
         JAXBContext jc = JAXBContext.newInstance(User.class);
         Unmarshaller unmarshaller = jc.createUnmarshaller();
         User user = (User) unmarshaller.unmarshal(doc);
         System.out.println(user.name);
     }
 ​
     static class User {
         public String name;
     }
 }

© 版权声明
THE END
喜欢就支持一下吧
点赞8赞赏 分享
评论 抢沙发

请登录后发表评论

    暂无评论内容