CodeQL 文档

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

点击查看 CodeQL 仓库中的查询

使用配置不当的 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)

参考资料

  • ©GitHub, Inc.
  • 条款
  • 隐私