XXE漏洞——XML实体定义引起的兼容性问题
一、XML基础知识
XML指可扩展的标记语言(Extensible Markup Language),类似于HTML(超文本标记语言);
XML被设计用来结构化、存储以及传输信息,其焦点是数据的内容;
XML没有任何预定义的标签,所有标签均由开发者自定义,开发者可以依据需要定制与业务匹配的结构化标签;
XML是对HTML的补充,在大多数WEB应用中,XML用于传输数据,HTML用于格式化并显示数据(XML是独立于软件和硬件的信息传输工具);
XML文档结构树包括XML声明、DTD文档类型定义(可选)、文档元素,这种树结构必须包含根节点,该节点是所有其他元素的父元素。
<?xml version="1.0" encoding="UTF-8"?><!--XML声明--> <!--文档类型定义--> <!DOCTYPE book [ <!ELEMENT book (bId, bName)> <!ELEMENT bId (#PCDATA)> <!ELEMENT bName (#PCDATA)> ]> <!--文档元素--> <books> <book> <bId>1</bId> <bName>Java编程思想</bName> </book> <book> <bId>2</bId> <bName>Python实战</bName> </book> </books>
DTD(文档类型定义)的作用是定义XML文档的合法构建模块,DTD可以在XML文档内声明,也可以引用外部的dtd文件。
内部声明DTD
<!DOCTYPE 根元素 [元素声明]>
引用外部DTD
<!DOCTYPE 根元素 SYSTEM "文件名">
or
<!DOCTYPE 根元素 PUBLIC "PUBLIC_ID" "文件名">
内部声明实体
<!ENTITY 实体名称 "实体的值">
引用外部实体
<!ENTITY 实体名称 SYSTEM "URI“>
or
<!ENTITY 实体名称 PUBLIC "PUBLIC_ID" "URI">
二、XML外部实体注入(XML External Entity)
当允许引用外部实体时,通过构造恶意内容,可导致读取文件、执行系统命令、占用内存、探测内网端口、攻击内网网站等危害。
引用外部实体的方式有多种,比如下面这种引用方式可以读取任意文件:
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE book [ <!ENTITY book SYSTEM "F:///etc/passwd"> ]> <books> <book> <bId>1</bId> <bName>&book;</bName> </book> </books>
实体注入除了可以读取文件之外,还可以将文件内容发送到攻击者网站、执行系统命令、探测内网端口、攻击内网网站等。
三、防御XXE攻击
方案一:使用开发语言提供的禁用外部实体的方法
Java:
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); dbf.setExpandEntityReferences(true);
Python:
from lxml import etree xmlData = etree.parse(xmlSource,etree.XMLParser(resolve_entities=False))
方案二:过滤用户提交的XML数据
关键词:<!DOCTYPE、<!ENTITI、SYSTEM、PUBLIC等
四、在浏览器中的体现
使用XML传输数据时,当数据中含有实体时,需要在文档定义中声明实体XML解析器才能正确的解析数据。
当数据中可能出现实体时,需要在文档声明中定义好实体内容;
这种处理比较简便,在大多数浏览器中也都可以正确解析数据,然而如果需要支持低版本的浏览器,那么这样处理去含有实体定义的XML数据就显得有点危险了。
例如,在IE9、IE8上,当浏览器试着去解析一个含有实体定义的XML数据时,由于该浏览器内部会将定义的实体当作实体注入攻击,因此数据解析遇到实体定义时,浏览器直接抛出异常。
解决方案:
方案一:
更换高版本浏览器,高版本浏览器不会对内部实体定义做处理。
方案二:
改用其他方式传输数据,如JSON。