XML 内部实体扩展¶
ID: py/xml-bomb
Kind: path-problem
Security severity: 7.5
Severity: warning
Precision: high
Tags:
- security
- external/cwe/cwe-776
- external/cwe/cwe-400
Query suites:
- python-code-scanning.qls
- python-security-extended.qls
- python-security-and-quality.qls
使用配置不当的 XML 解析器解析不受信任的 XML 文件可能会容易受到利用不受控制的内部实体扩展的拒绝服务 (DoS) 攻击。
在 XML 中,所谓的 *内部实体* 是一种机制,用于为一段文本或文档的一部分引入缩写。当配置为扩展实体的解析器遇到对内部实体的引用时,它会将实体替换为它所表示的数据。替换文本本身可能包含其他实体引用,这些引用会递归地扩展。这意味着实体扩展可以显着增加文档的大小。
如果使用启用了实体扩展的解析器解析不受信任的 XML,恶意攻击者可能会提交包含非常深层嵌套的实体定义的文档,导致解析器花费很长时间或使用大量内存。这有时被称为 *XML 炸弹* 攻击。
建议¶
防止 XML 炸弹攻击最安全的方法是在解析不受信任的数据时禁用实体扩展。是否可以这样做取决于所使用的库。请注意,一些库,例如 lxml
,默认启用了防止此类 DoS XML 攻击的措施,因此,除非您明确将 huge_tree
设置为 True
,否则无需采取进一步措施。
我们建议使用 defusedxml PyPI 包,该包专门用于防止 XML 攻击(包括 XXE 和 XML 炸弹)。
示例¶
以下示例使用 Python 标准库提供的 xml.etree
XML 解析器来解析字符串 xml_src
。该字符串来自不受信任的来源,因此这段代码容易受到 DoS 攻击,因为 xml.etree
XML 解析器默认扩展内部实体
from flask import Flask, request
import xml.etree.ElementTree as ET
app = Flask(__name__)
@app.post("/upload")
def upload():
xml_src = request.get_data()
doc = ET.fromstring(xml_src)
return ET.tostring(doc)
无法使用 xml.etree
防御内部实体扩展,因此,为了防御这些攻击,以下示例使用 defusedxml PyPI 包,该包不受此类内部实体扩展攻击的影响。
from flask import Flask, request
import defusedxml.ElementTree as ET
app = Flask(__name__)
@app.post("/upload")
def upload():
xml_src = request.get_data()
doc = ET.fromstring(xml_src)
return ET.tostring(doc)