🛡️ 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;
}
}
暂无评论内容