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


版权声明:本文为博主「Spoock」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。 原文链接:[Spoock's Blog | JAVA常见的XXE漏洞写法和防御](http://blog.spoock.com/2018/10/23/java-xxe/) ### 1.漏洞本质

  本质上xxe的漏洞都是因为对xml解析时允许引用外部实体,从而导致读取任意文件、探测内网端口、攻击内网网站、发起DoS拒绝服务攻击、执行系统命令等。

2.主要内容

2.1 主要漏洞及原因

  apache OFBiz中的XML解析是由UtilXml.java中readXmlDocument()完成,DocumentBuilderFactory设置不当,OFBiz为开源电子商务平台;
  JavaMelody中是由PayloadNameRequestWrapper.java中的parseSoapMethodName来解析XML,XMLStreamReader没有限制外部查询,JavaMelody属于java应用程序监控;
  微信支付SDK的XXE漏洞和Spring-data-XMLBean XXE漏洞都是是使用了DocumentBuilderFactory没有限制外部查询而导致XXE。

2.2 具体类库正确使用方法

DocumentBuilderFactory:注意代码先后顺序。
DocumentBuilder builder = dbf.newDocumentBuilder();
这行代码需要在dbf.setFeature()之后才能够生效;

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
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);

SAXBuilder:默认设置存在XXE,需要在新建实例的时候加上true参数:
SAXBuilder builder = new SAXBuilder(true);
或者:

1
2
3
4
5
6
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:默认存在问题,需要先setFeature,正确如下:

1
2
3
4
5
6
7
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:同上,先设置setFeature。正确如下:

1
2
3
4
5
6
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。虽然在运行时会报错,当时仍然能够触发XXE,正确如下:

1
2
3
4
5
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);

SchemaFactory:默认会存在XXE。虽然在运行时会报错,当时仍然能够触发XXE,正确如下:

1
2
3
4
5
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);

TransformerFactory:默认解析存在XXE。正确如下:

1
2
3
4
5
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。正确如下:

1
2
3
4
5
6
7
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。正确如下:

1
2
3
4
5
6
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:使用默认方式不会出现问题。(唯一不会出现问题的XML解析库)

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

2.2 正确方法总结

第一种:

1
2
3
4
"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

第二种:

1
2
XMLConstants.ACCESS_EXTERNAL_DTD, ""
XMLConstants.ACCESS_EXTERNAL_STYLESHEET, ""

3.参考文献

-------- 本文结束 感谢阅读 --------

本文标题:JAVA常见的XXE漏洞写法和防御转载

文章作者:FunctFan

发布时间:2020年06月19日 - 03:43:51

最后更新:2020年06月23日 - 22:23:21

原始链接:https://functfan.github.io/posts/2294213728/

许可协议: 署名-非商业性使用-禁止演绎 4.0 国际 转载请保留原文链接及作者。