版权声明:本文为博主「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漏洞写法和防御
- Java服务XXE漏洞防御方法