JAVA常见的XXE漏洞写法和防御

栏目: Java · 发布时间: 7年前

内容简介:貌似最近经常看到有Java项目爆出XXE的漏洞并且带有CVE,包括apache OFBiz中的XML解析是由我们就有理由相信XXE漏洞是由

貌似最近经常看到有 Java 项目爆出XXE的漏洞并且带有CVE,包括 Spring-data-XMLBean XXE漏洞JavaMelody组件XXE漏洞解析Apache OFBiz漏洞 。微信支付SDK的XXE漏洞。本质上xxe的漏洞都是因为对xml解析时允许引用外部实体,从而导致读取任意文件、探测内网端口、攻击内网网站、发起DoS拒绝服务攻击、执行系统命令等。

apache OFBiz中的XML解析是由 UtilXml.javareadXmlDocument() 完成的:

public static Document readXmlDocument(InputStream is, boolean validate, String docDescription)
            throws SAXException, ParserConfigurationException, java.io.IOException {
        //omit java code

        Document document = null;
        /* Standard JAXP (mostly), but doesn't seem to be doing XML Schema validation, so making sure that is on... */
        DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
        factory.setValidating(validate);
        factory.setNamespaceAware(true);

        factory.setAttribute("http://xml.org/sax/features/validation", validate);
        factory.setAttribute("http://apache.org/xml/features/validation/schema", validate);

        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/nonvalidating/load-external-dtd", false);
        factory.setXIncludeAware(false);
        factory.setExpandEntityReferences(false);

我们就有理由相信XXE漏洞是由 DocumentBuilderFactory 设置不当操作造成的,当然我们现在看到的是修改之后的版本;

JavaMelody 中是由 PayloadNameRequestWrapper.java 中的 parseSoapMethodName 来解析XML。

private static String parseSoapMethodName(InputStream stream, String charEncoding) {
	try {
		// newInstance() et pas newFactory() pour java 1.5 (issue 367)
		final XMLInputFactory factory = XMLInputFactory.newInstance();
		final XMLStreamReader xmlReader;
		if (charEncoding != null) {
			xmlReader = factory.createXMLStreamReader(stream, charEncoding);
		} else {
			xmlReader = factory.createXMLStreamReader(stream);
		}
		// omit java code
}

根据 JavaMelody组件XXE漏洞解析 的分析,是由于 xmlReader 没有限制外部查询导致的XXE漏洞。

同样地,微信支付SDK的XXE漏洞和Spring-data-XMLBean XXE漏洞都是是使用了 DocumentBuilderFactory 没有限制外部查询而导致XXE。

从这些例子中,可以发现在Java中其实存在着非常多的解析XML的库,同时由于在Java应用中会大量地使用到XML,因此就会出现使用不同的库对XML继续解析,而编写这些代码的研发人员并没有相关的安全背景,所以就导致了层出不穷地Java XXE漏洞。

不同库的Java XXE漏洞

我们测试的Payload很简单:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE root [
        <!ENTITY xxe SYSTEM "dnslog-ip">
        ]>
<evil>&xxe;</evil>

DocumentBuilderFactory

错误地修复方式

DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = dbf.newDocumentBuilder();
String FEATURE = null;
FEATURE = "http://javax.xml.XMLConstants/feature/secure-processing";
dbf.setFeature(FEATURE, true);
FEATURE = "http://apache.org/xml/features/disallow-doctype-decl";
dbf.setFeature(FEATURE, true);
FEATURE = "http://xml.org/sax/features/external-parameter-entities";
dbf.setFeature(FEATURE, false);
FEATURE = "http://xml.org/sax/features/external-general-entities";
dbf.setFeature(FEATURE, false);
FEATURE = "http://apache.org/xml/features/nonvalidating/load-external-dtd";
dbf.setFeature(FEATURE, false);
dbf.setXIncludeAware(false);
dbf.setExpandEntityReferences(false);
// 读取xml文件内容
FileInputStream fis = new FileInputStream("path/to/xxexml");
InputSource is = new InputSource(fis);
builder.parse(is);

看似设置得很很全面,但是直接仍然会被攻击,原因就是在于 DocumentBuilder builder = dbf.newDocumentBuilder(); 这行代码需要在 dbf.setFeature() 之后才能够生效;

正确地修复方式

DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
String FEATURE = null;
FEATURE = "http://javax.xml.XMLConstants/feature/secure-processing";
dbf.setFeature(FEATURE, true);
FEATURE = "http://apache.org/xml/features/disallow-doctype-decl";
dbf.setFeature(FEATURE, true);
FEATURE = "http://xml.org/sax/features/external-parameter-entities";
dbf.setFeature(FEATURE, false);
FEATURE = "http://xml.org/sax/features/external-general-entities";
dbf.setFeature(FEATURE, false);
FEATURE = "http://apache.org/xml/features/nonvalidating/load-external-dtd";
dbf.setFeature(FEATURE, false);
dbf.setXIncludeAware(false);
dbf.setExpandEntityReferences(false);
DocumentBuilder builder = dbf.newDocumentBuilder();
// 读取xml文件内容
FileInputStream fis = new FileInputStream("path/to/xxexml");
InputSource is = new InputSource(fis);
Document doc = builder.parse(is);

注意 DocumentBuilder builder = dbf.newDocumentBuilder(); 在两种不同的位置的差异性。

SAXBuilder

这个库貌似使用得不是很多。 SAXBuilder 如果使用默认配置就会触发XXE漏洞;如下

SAXBuilder builder = new SAXBuilder();
Document doc = builder.build(InputSource);

修复方法

方式1

SAXBuilder builder = new SAXBuilder(true);
Document doc = builder.build(InputSource);

方式2

SAXBuilder builder = new SAXBuilder();
builder.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
builder.setFeature("http://xml.org/sax/features/external-general-entities", false);
builder.setFeature("http://xml.org/sax/features/external-parameter-entities", false);
builder.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false);
Document doc = builder.build(InputSource);

SAXParserFactory

同样地,在默认配置下就会存在 XXE 漏洞。

SAXParserFactory spf = SAXParserFactory.newInstance();
SAXParser parser = spf.newSAXParser();
parser.parse(InputSource, (HandlerBase) null);

修复方法

SAXParserFactory spf = SAXParserFactory.newInstance();
spf.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
spf.setFeature("http://xml.org/sax/features/external-general-entities", false);
spf.setFeature("http://xml.org/sax/features/external-parameter-entities", false);
spf.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false);
SAXParser parser = spf.newSAXParser();
parser.parse(InputSource, (HandlerBase) null);

SAXReader

在默认情况下会出现 XXE 漏洞。

SAXReader saxReader = new SAXReader();
saxReader.read(InputSource);

修复方法

SAXReader saxReader = new SAXReader();
saxReader.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
saxReader.setFeature("http://xml.org/sax/features/external-general-entities", false);
saxReader.setFeature("http://xml.org/sax/features/external-parameter-entities", false);
saxReader.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false);
saxReader.read(InputSource);

SAXTransformerFactory

在默认情况下会出现 XXE 漏洞

SAXTransformerFactory sf = (SAXTransformerFactory) SAXTransformerFactory.newInstance();
StreamSource source = new StreamSource(InputSource);
sf.newTransformerHandler(source);

但是有趣的是,在默认配置,虽然能够触发XXE漏洞,但是出现运行时会报错;如下所示:

JAVA常见的XXE漏洞写法和防御

但是只是存在Web的解析记录。

修复方法

SAXTransformerFactory sf = (SAXTransformerFactory) SAXTransformerFactory.newInstance();
sf.setAttribute(XMLConstants.ACCESS_EXTERNAL_DTD, "");
sf.setAttribute(XMLConstants.ACCESS_EXTERNAL_STYLESHEET, "");
StreamSource source = new StreamSource(InputSource);
sf.newTransformerHandler(source);

通过跟踪源代码发现, XMLConstants.ACCESS_EXTERNAL_DTD 的内容是 http://javax.xml.XMLConstants/property/accessExternalDTD , XMLConstants.ACCESS_EXTERNAL_STYLESHEEThttp://javax.xml.XMLConstants/property/accessExternalStylesheet

SchemaFactory

在默认情况下也会出现 XXE 漏洞。

SchemaFactory factory = SchemaFactory.newInstance("http://www.w3.org/2001/XMLSchema");
StreamSource source = new StreamSource(ResourceUtils.getPoc1());
Schema schema = factory.newSchema(InputSource);

SAXTransformerFactory 虽然在运行时会报错,当时仍然能够触发 XXE

同样也只存在Web的解析记录。

修复方法

SchemaFactory factory = SchemaFactory.newInstance("http://www.w3.org/2001/XMLSchema");
factory.setProperty(XMLConstants.ACCESS_EXTERNAL_DTD, "");
factory.setProperty(XMLConstants.ACCESS_EXTERNAL_SCHEMA, "");
StreamSource source = new StreamSource(InputSource);
Schema schema = factory.newSchema(source);

SAXTransformerFactory 的修复原理一样就不作说明了。

TransformerFactory

使用默认的解析方法会存在 XXE 问题。

TransformerFactory tf = TransformerFactory.newInstance();
StreamSource source = new StreamSource(InputSource);
tf.newTransformer().transform(source, new DOMResult());

修复方法

TransformerFactory tf = TransformerFactory.newInstance();
tf.setAttribute(XMLConstants.ACCESS_EXTERNAL_DTD, "");
tf.setAttribute(XMLConstants.ACCESS_EXTERNAL_STYLESHEET, "");
StreamSource source = new StreamSourceInputSource);
tf.newTransformer().transform(source, new DOMResult());

ValidatorSample

使用默认的解析方法会存在 XXE 问题

SchemaFactory factory = SchemaFactory.newInstance("http://www.w3.org/2001/XMLSchema");
Schema schema = factory.newSchema();
Validator validator = schema.newValidator();
StreamSource source = new StreamSource(InputSource);
validator.validate(source);

修复方法

SchemaFactory factory = SchemaFactory.newInstance("http://www.w3.org/2001/XMLSchema");
Schema schema = factory.newSchema();
Validator validator = schema.newValidator();
validator.setProperty(XMLConstants.ACCESS_EXTERNAL_DTD, "");
validator.setProperty(XMLConstants.ACCESS_EXTERNAL_SCHEMA, "");
StreamSource source = new StreamSource(InputSource);
validator.validate(source);

XMLReader

使用默认的解析方法会存在 XXE 问题

XMLReader reader = XMLReaderFactory.createXMLReader();
reader.parse(new InputSource(InputSource));

修复方法

XMLReader reader = XMLReaderFactory.createXMLReader();
reader.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
reader.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false);
reader.setFeature("http://xml.org/sax/features/external-general-entities", false);
reader.setFeature("http://xml.org/sax/features/external-parameter-entities", false);
reader.parse(new InputSource(InputSource));

Unmarshaller

使用默认的解析方法不会存在 XXE 问题,这也是唯一一个使用默认的解析方法不会存在 XXE 的一个库。

Class tClass = Some.class;
JAXBContext context = JAXBContext.newInstance(tClass);
Unmarshaller um = context.createUnmarshaller();
Object o = um.unmarshal(ResourceUtils.getPoc1());
tClass.cast(o);

总结

其实,通过对不同的XML解析库的修复方式可以发现, XXE 的防护值需要限制带外实体的注入就可以了,修复方式也简单,需要设置几个选项为发 false 即可,可能少许的几个库可能还需要设置一些其他的配置,但是都是类似的。

总体来说修复方式都是通过设置feature的方式来防御 XXE 。两种方法分别是:

"http://apache.org/xml/features/disallow-doctype-decl", true 
"http://apache.org/xml/features/nonvalidating/load-external-dtd", false
"http://xml.org/sax/features/external-general-entities", false
"http://xml.org/sax/features/external-parameter-entities", false

配置如上。

另外一种是:

XMLConstants.ACCESS_EXTERNAL_DTD, ""
XMLConstants.ACCESS_EXTERNAL_STYLESHEET, ""

本质上 XXE 的问题就是一个配置不当的问题,即容易发现也容易防御,但是前提是需要知道有这个漏洞,这也是就是很多开发人员因为不知道 XXE 最终写出了含有漏洞的代码。

以上。


以上所述就是小编给大家介绍的《JAVA常见的XXE漏洞写法和防御》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

The Zen of CSS Design

The Zen of CSS Design

Dave Shea、Molly E. Holzschlag / Peachpit Press / 2005-2-27 / USD 44.99

Proving once and for all that standards-compliant design does not equal dull design, this inspiring tome uses examples from the landmark CSS Zen Garden site as the foundation for discussions on how to......一起来看看 《The Zen of CSS Design》 这本书的介绍吧!

html转js在线工具
html转js在线工具

html转js在线工具

正则表达式在线测试
正则表达式在线测试

正则表达式在线测试

HSV CMYK 转换工具
HSV CMYK 转换工具

HSV CMYK互换工具