xml实体攻击
分为外部实体攻击和内部实体攻击。
外部通用实体举例:
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE admin[
<!ENTITY user SYSTEM "file:///D:/user.txt">
]>
<user><username>&user;</username><age>12</age></user>
user.txt如下:
chuchu
最终拿到的xml是这样的:
<user><username>chuchu</username><age>12</age></user>
相当于xml为我们提供了一种动态设置标签值的强大能力(果然每种语言都有要成为通用语言的野心啊。。。)
外部实体还有一种类型叫“参数实体”,其所能提供的动态能力更强,当然,可能更危险。
外部实体的英文翻译是XXE(Xml eXternal Entity)。
内部实体举例:
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE a1 [
<!ENTITY a1 "a1">
<!ENTITY a2 "&a1;&a1;&a1;&a1;&a1;&a1;&a1;">
<!ENTITY a3 "&a2;&a2;&a2;&a2;&a2;&a2;&a2;">
<!ENTITY a4 "&a3;&a3;&a3;&a3;&a3;&a3;&a3;">
]>
<user><username>&a4;</username><age>12</age></user>
内部实体可以递归展开,常用来做XML Entity Expansion攻击,造成Dos(Denial of service)。
解决方法
如果我们用sax解析xml,通常可使用:
SAXReader.createDefault
该方法会禁掉如下一些实体特性:
public static SAXReader createDefault() {
SAXReader reader = new SAXReader();
try {
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);
} catch (SAXException var2) {
}
return reader;
}
也可使用XMLHelper.newXMLReader(),这样创出来的XMLReader连disallow-doctype-decl都设置为true,能防范所有的xml实体攻击。
这些feature的详细说明:
// This is the PRIMARY defense. If DTDs (doctypes) are disallowed, almost all
// XML entity attacks are prevented
// Xerces 2 only - http://xerces.apache.org/xerces2-j/features.html#disallow-doctype-decl
// 因为实体都定义在doctype里,所以禁掉doctype,无论外部还是内部实体攻击就都不存在了
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
// 禁掉外部通用实体(external general entity)。
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
// 禁掉外部参数实体(external general entity)。
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);
结论:
- 防御外部实体攻击,可以设置external-general-entities和external-parameter-entities选项为false
- 防御内部实体展开攻击,似乎只能设置disallow-doctype-decl为true了
排查方法
顺带说一下排查方法,可搜索如下关键字:
SAXReader、XMLReader、SAXParser、DocumentBuilder、SAXBuilder
上述都是常用的xml解析库里的类。
我们只要看new出parser或reader实例的地方有没有设置防范实体攻击的feature即可,例如:
// 如果不需要 inline DOCTYPE 声明,可使用以下属性将其完全禁用,几乎可以阻止所有的XML实体攻击。
factory.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
factory.setFeature("http://javax.xml.XMLConstants/feature/secure-processing", true);
// 是否包含外部生成的实体。
factory.setFeature("http://xml.org/sax/features/external-general-entities", false);
// 是否包含外部的参数,包括外部DTD子集。
factory.setFeature("http://xml.org/sax/features/external-parameter-entities", false);
// 禁止DTDS外部引用文件
factory.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false);