转载

Java-XXE-总结

同事问我研究过Java下的xxe漏洞嘛,为啥修复建议不起作用,emmmm然后这个问题我就回答不上来了,这个问题有两个关注点:

1.java下xxe产生的原理是啥。

2.修复建议的修复代码是啥。

0x02 深入分析

1.DocumentBuilder

原理分析

测试代码:

package com.l1nk3r.xxe.javaxxe;
import org.w3c.dom.Document;
import javax.xml.parsers.*;
import java.io.ByteArrayInputStream;
import java.io.InputStream;

public class DocumentXXE {
public static void main(String[] args) throws  Exception {
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
DocumentBuilder db = dbf.newDocumentBuilder();
String str = "<!DOCTYPE doc [ /n" +
"<!ENTITY xxe SYSTEM /"http://127.0.0.1:8888/">/n" +
"]><doc>&xxe;</doc>";
InputStream is = new ByteArrayInputStream(str.getBytes());
Document doc = db.parse(is);
}
}

db.parse 处下个断点,代码来到这个 Java.xml.parsers.DocumentBuilder#parse 类中,跟进 return parse

Java-XXE-总结

DocumentBuilderImpl#parse 中,调用了 DOMParser#parse

Java-XXE-总结

跟进 DOMParser#parse 这个方法,调用 parse 方法来解析 xmlInputSource

Java-XXE-总结

跟进 XMLParser#parse ,调用 fConfiguration.parse 方法。

Java-XXE-总结

而这个 fConfiguration.parse 实际上是个继承接口,这里根据 debug 会进入 XML11Configuration#parse 中。

Java-XXE-总结

Java-XXE-总结

通过 setInputSource(source) 方法将 Xml 数据赋值给 fInputSource ,然后调用 parse(boolean complete) 构造方法进行处理。

Java-XXE-总结

跟进 parse(boolean complete) 方法,然后就来到了 XMLDocumentFragmentScannerImpl#scanDocument 方法中。

Java-XXE-总结

跟进 XMLDocumentFragmentScannerImpl#scanDocument 方法,这个方法首先会针对xml数据流中的 document 部分进行扫描。

Java-XXE-总结

然后就会扫描xml数据流中的 DTD 部分。

Java-XXE-总结

最后开始扫描 ELEMENT 部分。

Java-XXE-总结

然后调用 next 方法。

Java-XXE-总结

跟进 XMLDocumentFragmentScannerImpl#next ,这个方法会针对一些特殊字符进行标记。

Java-XXE-总结

而我们刚刚payload: <doc>&xxe;</doc> 里面存在 & 特殊字符,所以这里会调用 setScannerState 构造方法将 fScannerState 设置为 SCANNER_STATE_REFERENCE

Java-XXE-总结

代码继续往下走,会来到 XMLDocumentFragmentScannerImpl#next 方法中的下图代码位置,我们已经知道这时候的 fScannerStateSCANNER_STATE_REFERENCE ,所以这里的 case 应该要来到 SCANNER_STATE_REFERENCE 中。

Java-XXE-总结

Java-XXE-总结

SCANNER_STATE_REFERENCE 这个case中,会调用 scanEntityReference 来处理 fContentBuffer 中的数据。跟进 scanEntityReference 方法,首先会获取 scanName ,我们payload里面的name自然是xxe,所以这里debug的结果也是xxe。

Java-XXE-总结

代码继续下行,来到下图位置,调用 XMLEntityManager#startEntity 进行处理。

Java-XXE-总结

跟进 XMLEntityManager#startEntity 最后会调用 startEntity(String name,XMLInputSource xmlInputSource,boolean literal, boolean isExternal) 这个构造方法,并且可以看到已经解析了payload中的外部地址。

Java-XXE-总结

startEntity 方法中调用了 setupCurrentEntity 方法。

Java-XXE-总结

跟进 XMLEntityManager#setupCurrentEntity ,这里可以看到解析了我们payload中的地址,并且发起了http的请求。

Java-XXE-总结

实际调用栈

setupCurrentEntity:646, XMLEntityManager (com.sun.org.apache.xerces.internal.impl)
startEntity:1300, XMLEntityManager (com.sun.org.apache.xerces.internal.impl)
startEntity:1237, XMLEntityManager (com.sun.org.apache.xerces.internal.impl)
scanEntityReference:1908, XMLDocumentFragmentScannerImpl (com.sun.org.apache.xerces.internal.impl)
next:3067, XMLDocumentFragmentScannerImpl$FragmentContentDriver (com.sun.org.apache.xerces.internal.impl)
next:606, XMLDocumentScannerImpl (com.sun.org.apache.xerces.internal.impl)
scanDocument:510, XMLDocumentFragmentScannerImpl (com.sun.org.apache.xerces.internal.impl)
parse:848, XML11Configuration (com.sun.org.apache.xerces.internal.parsers)
parse:777, XML11Configuration (com.sun.org.apache.xerces.internal.parsers)
parse:141, XMLParser (com.sun.org.apache.xerces.internal.parsers)
parse:243, DOMParser (com.sun.org.apache.xerces.internal.parsers)
parse:348, DocumentBuilderImpl (com.sun.org.apache.xerces.internal.jaxp)
parse:121, DocumentBuilder (javax.xml.parsers)
main:19, DocumentXXE (com.l1nk3r.xxe.javaxxe)

代码流程图

Java-XXE-总结

漏洞修复

错误的修复方式

目前百度查询xxe的修复方式实际上有这么一段代码,但是这么一段代码实际上是不会生效。

Java-XXE-总结

看看为啥不起作用,可以选择在 dbf.setExpandEntityReferences(false); 下一个断点。 DocumentBuilderFactoryImpl 这个类中的 expandEntityRef 变量的值默认是true,通过 setExpandEntityReferences(false) 之后将 expandEntityRef 变量的值设置为false。

Java-XXE-总结

代码继续下行来到 dbf.newDocumentBuilder 中。

Java-XXE-总结

该方法会返回一个实例化的 DocumentBuilderFactoryImpl 对象。

Java-XXE-总结

而在 DocumentBuilderFactoryImpl 这个对象中,会根据刚刚的 expandEntityRef 的值取反之后赋值给 CREATE_ENTITY_REF_NODES_FEATURE ,也就是 http://apache.org/xml/features/dom/create-entity-ref-nodes ,对应的结果为 true

Java-XXE-总结

最后这里处理完之后自然返回 DocumentBuilderFactoryImpl 对象,代码继续下行来到 parse 处。

Java-XXE-总结

前面步骤省略,和之前一致,来到 XMLParser#parse 这里之后,这里有个 reset 方法。

Java-XXE-总结

跟进这个 reset 方法,实际上来到了 AbstractDOMParser#reset 中,并且将 fCreateEntityRefNodes 的值设置为我们刚刚修改过,也就是 true 这个值。

Java-XXE-总结

这是到这部分的调用栈

Java-XXE-总结

之后代码继续下行,在 XMLDocumentFragmentScannerImpl#scanDocument 方法中,会先扫描 document 部分,再扫描 DTD 部分,最后扫描 ELEMENT 部分。 XMLDocumentFragmentScannerImpl#next 会针对 & 进行标记,调用 scanEntityReference 方法将 fScannerState 设置为 SCANNER_STATE_REFERENCE ,最后依然会调用 setupCurrentEntity 创建连接并发起请求,以获取外部实体的内容。

然后继续往下走来到 XMLEntityManager#endEntity ,经过一系列调用会来到 AbstractDOMParser#endGeneralEntity 中,会判断前面设置的 fCreateEntityRefNodes 的值,如果为 true则展开实体引用到生成的文档中替换掉 &xxx 的实体引用声明,设置为false则保留实体引用声明的DOM树在生成的文档中。

Java-XXE-总结

此方法作用于XML解析后生成的文档。setExpandEntityReferences设置为true则展开实体引用到生成的文档中替换掉&xx的实体引用声明,setExpandEntityReferences设置为false则保留实体引用声明的DOM树在生成的文档中。

Java-XXE-总结

正确的修复方式

DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();     
/*以下为修复代码*/            //https://www.owasp.org/index.php/XML_External_Entity_(XXE)_Prevention_Cheat_Sheet#Java
//禁用DTDs (doctypes),几乎可以防御所有xml实体攻击
dbf.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true); //首选
//如果不能禁用DTDs,可以使用下两项,必须两项同时存在
dbf.setFeature("http://xml.org/sax/features/external-general-entities", false);        //防止外部实体POC 
dbf.setFeature("http://xml.org/sax/features/external-parameter-entities", false);   //防止参数实体POC
/*以上为修复代码*/    
DocumentBuilder db = dbf.newDocumentBuilder();        
Document doc = db.parse(request.getInputStream());

当然如果还不放心的话,下面是owasp推荐的,其实也就是多了三个属性的设置,具体可以看看下面

DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
String FEATURE = null;
try {
FEATURE = "http://apache.org/xml/features/disallow-doctype-decl";
dbf.setFeature(FEATURE, true);
// If you can't completely disable DTDs, then at least do the following:
// Xerces 1 - http://xerces.apache.org/xerces-j/features.html#external-general-entities
// Xerces 2 - http://xerces.apache.org/xerces2-j/features.html#external-general-entities
// JDK7+ - http://xml.org/sax/features/external-general-entities
FEATURE = "http://xml.org/sax/features/external-general-entities";
dbf.setFeature(FEATURE, false);
// Xerces 1 - http://xerces.apache.org/xerces-j/features.html#external-parameter-entities
// Xerces 2 - http://xerces.apache.org/xerces2-j/features.html#external-parameter-entities
// JDK7+ - http://xml.org/sax/features/external-parameter-entities
FEATURE = "http://xml.org/sax/features/external-parameter-entities";
dbf.setFeature(FEATURE, false);
// Disable external DTDs as well
FEATURE = "http://apache.org/xml/features/nonvalidating/load-external-dtd";
dbf.setFeature(FEATURE, false);
// and these as well, per Timothy Morgan's 2014 paper: "XML Schema, DTD, and Entity Attacks"
dbf.setXIncludeAware(false);
dbf.setExpandEntityReferences(false);
>..
// Load XML file or stream using a XXE agnostic configured parser...
DocumentBuilder safebuilder = dbf.newDocumentBuilder();

当然还是需要看一下原理,选择在下面这个位置代码下个断点。

dbf.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true)

前面我们在错误修复方法里面,在 dbf.setExpandEntityReferences(false); 的时候,我们知道在 DocumentBuilderImpl 类中,调用 domParser.setFeatureexpandEntityRef 取反之后赋值给 CREATE_ENTITY_REF_NODES_FEATURE ,之后调用 reset 方法的时候将 fCreateEntityRefNodes 的设置为 CREATE_ENTITY_REF_NODES_FEATURE 的结果。

回到现在这个设置,有点不太一样,在 DocumentBuilderImpl 类中找不到我们设置的这个 disallow-doctype-decl 的配置,因此会继续向下,下图是在 DocumentBuilderImpl 中第234行,调用 setFeatures 方法。

Java-XXE-总结

这个方法会继续向下行,来到了 XMLDocumentScannerImpl#setFeature 中,并且将 fDisallowDoctype 设置为 true ,这是整个 setFeature 操作过程中的调用链。

Java-XXE-总结

紧接着进入到 XMLDocumentFragmentScannerImpl#scanDocument ,我们知道首先会扫描 document 部分,然后调用 XMLDocumentScannerImpl$PrologDriver#next 方法。

Java-XXE-总结

XMLDocumentScannerImpl$PrologDriver#next 方法中,调用 setScannerStatefScannerState 设置为24,也就是 SCANNER_STATE_DOCTYPE 属性。

Java-XXE-总结

Java-XXE-总结

紧接着代码继续下行,根据 fScannerState 进行选择,这里我们前面的 fScannerState 的状态设置为了 SCANNER_STATE_DOCTYPE ,所以自然进入这个case中,然后针对我们之前的 fDisallowDoctype 属性进行判断,如果是true的话,就抛出异常。

Java-XXE-总结

这是到这个部分的调用栈。

Java-XXE-总结

异常会被抛到 XML11Configuration.parse() 中处理。处理的结果是 fParseInProgress 变量被设置为了 false ,接着会调用 cleanup() 方法在完全解析XML文档之前终止解析,这个是到最后终止部分的调用栈。

Java-XXE-总结

Java-XXE-总结

2.SAXBuilder

原理分析

测试代码:

package com.l1nk3r.xxe.javaxxe;

import java.io.ByteArrayInputStream;
import java.io.InputStream;
import org.jdom2.Document;d
import org.jdom2.input.SAXBuilder;

public class SAXBuilderXxe {
public static void main(String[] args) throws  Exception {
String str = "<!DOCTYPE doc [ /n" +
"<!ENTITY xxe SYSTEM /"http://127.0.0.1:8888/">/n" +
"]><doc>&xxe;</doc>";
InputStream is = new ByteArrayInputStream(str.getBytes());
SAXBuilder sb = new SAXBuilder();
Document doc = sb.build(is);
}
}

下图是这个方法到触发xxe的调用栈,可以看到画圈的部分和我们前面分析的 DocumentBuilder 中造成xxe的调用栈基本相似,最后都是到 XMLEntityManager#setupCurrentEntity 中触发xxe。

Java-XXE-总结

修复建议

修复建议可以参考下列代码,注意实例化 SAXBuilder 类和 build 方法解析之间的这些属性。

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

可以看到实际上将 disallow-doctype-decl 设置为true之后,就会抛出以下报错,具体原因和 DocumentBuilder 一致。

Java-XXE-总结

3.SAXParserFactory

原理分析

测试代码:

package com.l1nk3r.xxe.javaxxe;

import org.xml.sax.HandlerBase;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;

public class SAXParseFactoryXxe {
public static void main(String[] args) throws  Exception {
String str = "<!DOCTYPE doc [ /n" +
"<!ENTITY xxe SYSTEM /"http://127.0.0.1:8888/">/n" +
"]><doc>&xxe;</doc>";
InputStream is = new ByteArrayInputStream(str.getBytes());
SAXParserFactory spf = SAXParserFactory.newInstance();
SAXParser parser = spf.newSAXParser();
parser.parse(is, (HandlerBase) null);
}
}

默认情况下也存在xxe,具体看下图调用栈就懂了。

Java-XXE-总结

修复建议

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();

4.SAXTransformerFactory

漏洞原理

测试代码:

package com.l1nk3r.xxe.javaxxe;

import javax.xml.transform.sax.SAXTransformerFactory;
import javax.xml.transform.stream.StreamSource;
import java.io.ByteArrayInputStream;
import java.io.InputStream;

public class SAXTransformerFactoryXxe {
public static void main(String[] args) throws  Exception {
String str = "<!DOCTYPE doc [ /n" +
"<!ENTITY xxe SYSTEM /"http://127.0.0.1:8888/">/n" +
"]><doc>&xxe;</doc>";
InputStream is = new ByteArrayInputStream(str.getBytes());
SAXTransformerFactory sf = (SAXTransformerFactory) SAXTransformerFactory.newInstance();
StreamSource source = new StreamSource(is);
sf.newTransformerHandler(source);
}
}

调用栈:

Java-XXE-总结

修复建议

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

5.SAXReader

漏洞原理

测试代码:

package com.l1nk3r.xxe.javaxxe;

import java.io.ByteArrayInputStream;
import java.io.InputStream;
import org.dom4j.io.SAXReader;

public class SAXReaderXxe {
public static void main(String[] args) throws  Exception {
String str = "<!DOCTYPE doc [ /n" +
"<!ENTITY xxe SYSTEM /"http://127.0.0.1:8888/">/n" +
"]><doc>&xxe;</doc>";
InputStream is = new ByteArrayInputStream(str.getBytes());
SAXReader saxReader = new SAXReader();
saxReader.read(is);
}
}

调用栈

Java-XXE-总结

修复建议

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(is);

6.XMLReader

漏洞原理

测试代码:

package com.l1nk3r.xxe.javaxxe;

import org.xml.sax.InputSource;
import org.xml.sax.XMLReader;
import org.xml.sax.helpers.XMLReaderFactory;

import java.io.ByteArrayInputStream;
import java.io.InputStream;

public class XMLReaderXxe {
public static void main(String[] args) throws Exception {
String str = "<!DOCTYPE doc [ /n" +
"<!ENTITY xxe SYSTEM /"http://127.0.0.1:8888/">/n" +
"]><doc>&xxe;</doc>";
InputStream is = new ByteArrayInputStream(str.getBytes());
XMLReader reader = XMLReaderFactory.createXMLReader();
reader.parse(new InputSource(is));
}
}

调用栈:

Java-XXE-总结

修复建议

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(is));

7.SchemaFactory

漏洞原理

测试代码:

package com.l1nk3r.xxe.javaxxe;

import javax.xml.transform.stream.StreamSource;
import javax.xml.validation.Schema;
import javax.xml.validation.SchemaFactory;
import java.io.ByteArrayInputStream;
import java.io.InputStream;

public class SchemaFactoryXxe {
public static void main(String[] args) throws Exception {
String str = "<!DOCTYPE doc [ /n" +
"<!ENTITY xxe SYSTEM /"http://127.0.0.1:8888/">/n" +
"]><doc>&xxe;</doc>";
InputStream is = new ByteArrayInputStream(str.getBytes());
SchemaFactory factory = SchemaFactory.newInstance("http://www.w3.org/2001/XMLSchema");
StreamSource source = new StreamSource(is);
Schema schema = factory.newSchema(source);
}
}

调用栈:

Java-XXE-总结

修复建议

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(is);
Schema schema = factory.newSchema(source);

8.XMLInputFactory

漏洞原理

测试代码:

package com.l1nk3r.xxe.javaxxe;

import javax.xml.stream.XMLInputFactory;
import javax.xml.stream.XMLStreamConstants;
import javax.xml.stream.XMLStreamReader;

public class XMLInputFactoryXxe {
public static void main(String[] args) throws Exception {
XMLInputFactory xmlInputFactory = XMLInputFactory.newFactory();
XMLStreamReader reader = xmlInputFactory.createXMLStreamReader(ResourceUtils.getPoc1());
try {
while (reader.hasNext()) {
int type = reader.next();
if (type == XMLStreamConstants.START_ELEMENT) {//开始节点
System.out.print(reader.getName());
} else if (type == XMLStreamConstants.CHARACTERS) {//表示事件字符
System.out.println("type" + type);
} else if (type == XMLStreamConstants.END_ELEMENT) {//结束节点
System.out.println(reader.getName());
}
}
reader.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
package com.l1nk3r.xxe.javaxxe;

import java.io.InputStream;

public class ResourceUtils {
public static InputStream getPoc1() {
return ResourceUtils.class.getClassLoader().getResourceAsStream("poc1.xml");
}
}

调用栈:

Java-XXE-总结

修复建议

XMLInputFactory xmlInputFactory = XMLInputFactory.newFactory();
xmlInputFactory.setProperty(XMLInputFactory.SUPPORT_DTD, false); 
xmlInputFactory.setProperty(XMLInputFactory.IS_SUPPORTING_EXTERNAL_ENTITIES, false);
XMLStreamReader reader = xmlInputFactory.createXMLStreamReader(ResourceUtils.getPoc1());

9.TransformerFactory

漏洞原理

测试代码:

package com.l1nk3r.xxe.javaxxe;

import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMResult;
import javax.xml.transform.stream.StreamSource;
import java.io.ByteArrayInputStream;
import java.io.InputStream;

public class TransformerFactoryXxe {
public static void main(String[] args) throws  Exception {
String str = "<!DOCTYPE doc [ /n" +
"<!ENTITY xxe SYSTEM /"http://127.0.0.1:8888/">/n" +
"]><doc>&xxe;</doc>";
InputStream is = new ByteArrayInputStream(str.getBytes());
TransformerFactory tf = TransformerFactory.newInstance();
StreamSource source = new StreamSource(is);
tf.newTransformer().transform(source, new DOMResult());
}
}

调用栈:

Java-XXE-总结

修复建议

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

10.Validator

漏洞原理

测试代码:

package com.l1nk3r.xxe.javaxxe;

import javax.xml.transform.stream.StreamSource;
import javax.xml.validation.Schema;
import javax.xml.validation.SchemaFactory;
import javax.xml.validation.Validator;
import java.io.ByteArrayInputStream;
import java.io.InputStream;

public class ValidatorSampleXxe {
public static void main(String[] args) throws  Exception {
String str = "<!DOCTYPE doc [ /n" +
"<!ENTITY xxe SYSTEM /"http://127.0.0.1:8888/">/n" +
"]><doc>&xxe;</doc>";
InputStream is = new ByteArrayInputStream(str.getBytes());
SchemaFactory factory = SchemaFactory.newInstance("http://www.w3.org/2001/XMLSchema");
Schema schema = factory.newSchema();
Validator validator = schema.newValidator();
StreamSource source = new StreamSource(is);
validator.validate(source);
}
}

调用栈:

Java-XXE-总结

修复建议

Schema schema = factory.newSchema();
Validator validator = schema.newValidator();
validator.setProperty(XMLConstants.ACCESS_EXTERNAL_DTD, "");
validator.setProperty(XMLConstants.ACCESS_EXTERNAL_SCHEMA, "");
StreamSource source = new StreamSource(is);
validator.validate(source);

11.Unmarshaller

测试代码:

package com.l1nk3r.xxe.javaxxe;

import javax.xml.bind.JAXBContext;
import javax.xml.bind.Unmarshaller;

public class UnmarshallerXxe {
public static void main(String[] args) throws  Exception {
Class tClass = UnmarshallerXxe.class;
JAXBContext context = JAXBContext.newInstance(tClass);
Unmarshaller um = context.createUnmarshaller();
Object o = um.unmarshal(ResourceUtils.getPoc1());
tClass.cast(o);
}
}

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

0x03 小结

通过上面的总结,默认情况下用 Unmarshaller 来处理xml不会发生xxe的问题。我们可以看到调用栈的过程中,存在xxe问题的库或者类实际上最后底层调用都是jdk自身处理xml的类,最后的核心触发流程都会来到 XMLEntityManager#setupCurrentEntity 当中。

针对修复方式实际上也是两种:

其一是通过setfeature的方式来防御 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 这个类的一些配置来进行修复:

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

实际上通常禁用DTD,就ok了。但是由于一些实际业务情况,无法禁用DTD,这时候建议禁用通用实体和参数实体一起配置,因为禁用了通用实体就不会被回显,禁用了参数实体就不会被外带查询。

当然xml配置中还有很多冗余部分,具体可以看看前文 DocumentBuilder 中正确修复方式中的一些官方给的配置。

最后当然再提一个小建议,修复XXE建议采取最小化原则。如果一股脑将这些参数全部禁用或者限制,可能会出现一些奇怪的bug。

原文  http://www.lmxspace.com/2019/10/31/Java-XXE-总结/
正文到此结束
Loading...