Django SQL注入历史漏洞分析
字数 1714 2025-08-27 12:33:37

Django SQL注入历史漏洞分析教学文档

前言

本文档详细分析Django框架中三个重要的SQL注入历史漏洞:CVE-2020-7471、CVE-2021-35042和CVE-2022-28346。这些漏洞涉及Django的不同版本和组件,通过分析这些漏洞可以帮助开发者理解Django的安全机制和防范SQL注入的最佳实践。

CVE-2020-7471: StringAgg分隔符注入

漏洞概述

  • 影响版本:Django 1.11.x < 1.11.28, 2.2.x < 2.2.10, 3.0.x < 3.0.3
  • 漏洞位置:contrib.postgres.aggregates.StringAgg聚合函数的delimiter参数
  • 漏洞描述:当使用不受信任的数据作为StringAgg的分隔符时,攻击者可构造恶意分隔符绕过转义机制,注入SQL代码

漏洞分析

  1. StringAgg函数:将输入值使用指定分隔符连接起来
  2. 漏洞点:分隔符参数未经过适当转义直接嵌入SQL语句
  3. PoC验证
    • 当分隔符为单引号时,SQL语句会报错,显示未转义的单引号
    • 构造payload:')--可注释掉后续SQL语句

漏洞利用

# 构造恶意查询
results = Info.objects.all().values('gender').annotate(
    mydefinedname=StringAgg('name', delimiter="')--")
)

修复方案

官方通过引入django.db.models.Value来防御:

delimiter_expr = Value(str(delimiter))

Value函数会将参数加入sql parameter list,经过Django内置过滤机制处理

CVE-2021-35042: order_by()注入

漏洞概述

  • 影响版本:Django 3.1.x < 3.1.13, 3.2.x < 3.2.5
  • 漏洞位置:QuerySet.order_by()方法
  • 漏洞描述:当order_by参数来自不可信的客户端输入时,攻击者可构造恶意输入进行SQL注入

漏洞分析

  1. order_by处理流程
    • 调用clear_ordering()清除原有排序
    • 调用add_ordering()添加新排序条件
  2. 关键漏洞点
    • 带点号(.)的字段名会跳过列名有效性检查
    • get_order_by()函数中列名部分未经过滤

漏洞利用

# 恶意请求示例
User.objects.order_by("app_user.name);select updatexml(1, concat(0x7e,(select @@version)),1)#")

修复方案

  1. 严格验证order_by参数
  2. 对列名部分也进行过滤处理

CVE-2022-28346: annotate/aggregate/extra别名注入

漏洞概述

  • 影响版本:Django 2.2.x < 2.2.28, 3.2.x < 3.2.13, 4.0.x < 4.0.4
  • 漏洞位置:QuerySet.annotate(), aggregate(), extra()方法
  • 漏洞描述:当使用字典展开(**kwargs)传递列别名时,恶意构造的字典可导致SQL注入

漏洞分析

  1. 处理流程
    • annotate()调用_annotate并传入kwargs
    • 将kwargs更新到annotations中
    • 遍历annotations调用add_annotation
  2. 漏洞点
    • resolve_expression解析过程中未对聚合参数进行充分检查
    • 别名部分可直接注入SQL代码

修复方案

  1. 严格验证annotate/aggregate/extra的kwargs参数
  2. 对列别名进行转义处理

总结与防御建议

漏洞共性

  1. 都涉及Django ORM中参数处理不严谨
  2. 都允许通过精心构造的参数注入SQL代码
  3. 都影响多个Django版本

防御措施

  1. 及时更新:保持Django版本为最新安全版本
  2. 输入验证
    • 对所有用户提供的参数进行严格验证
    • 使用Django提供的安全函数(如Value)处理参数
  3. 最小权限原则:数据库连接使用最小必要权限
  4. 安全编码实践
    • 避免直接拼接用户输入到查询中
    • 使用参数化查询
    • 对特殊字符进行转义

开发者检查清单

  1. 检查项目中是否使用了受影响版本的Django
  2. 审查代码中是否直接使用用户输入作为查询参数
  3. 确保所有动态查询都使用Django的安全机制处理
  4. 对关键业务功能进行安全测试

通过深入理解这些漏洞的原理和修复方案,开发者可以更好地编写安全的Django应用程序,避免类似的SQL注入风险。

Django SQL注入历史漏洞分析教学文档 前言 本文档详细分析Django框架中三个重要的SQL注入历史漏洞:CVE-2020-7471、CVE-2021-35042和CVE-2022-28346。这些漏洞涉及Django的不同版本和组件,通过分析这些漏洞可以帮助开发者理解Django的安全机制和防范SQL注入的最佳实践。 CVE-2020-7471: StringAgg分隔符注入 漏洞概述 影响版本:Django 1.11.x < 1.11.28, 2.2.x < 2.2.10, 3.0.x < 3.0.3 漏洞位置: contrib.postgres.aggregates.StringAgg 聚合函数的 delimiter 参数 漏洞描述:当使用不受信任的数据作为StringAgg的分隔符时,攻击者可构造恶意分隔符绕过转义机制,注入SQL代码 漏洞分析 StringAgg函数 :将输入值使用指定分隔符连接起来 漏洞点 :分隔符参数未经过适当转义直接嵌入SQL语句 PoC验证 : 当分隔符为单引号时,SQL语句会报错,显示未转义的单引号 构造payload: ')-- 可注释掉后续SQL语句 漏洞利用 修复方案 官方通过引入 django.db.models.Value 来防御: Value 函数会将参数加入sql parameter list,经过Django内置过滤机制处理 CVE-2021-35042: order_ by()注入 漏洞概述 影响版本:Django 3.1.x < 3.1.13, 3.2.x < 3.2.5 漏洞位置: QuerySet.order_by() 方法 漏洞描述:当order_ by参数来自不可信的客户端输入时,攻击者可构造恶意输入进行SQL注入 漏洞分析 order_ by处理流程 : 调用 clear_ordering() 清除原有排序 调用 add_ordering() 添加新排序条件 关键漏洞点 : 带点号(.)的字段名会跳过列名有效性检查 get_order_by() 函数中列名部分未经过滤 漏洞利用 修复方案 严格验证order_ by参数 对列名部分也进行过滤处理 CVE-2022-28346: annotate/aggregate/extra别名注入 漏洞概述 影响版本:Django 2.2.x < 2.2.28, 3.2.x < 3.2.13, 4.0.x < 4.0.4 漏洞位置: QuerySet.annotate() , aggregate() , extra() 方法 漏洞描述:当使用字典展开(** kwargs)传递列别名时,恶意构造的字典可导致SQL注入 漏洞分析 处理流程 : annotate() 调用 _annotate 并传入kwargs 将kwargs更新到annotations中 遍历annotations调用 add_annotation 漏洞点 : 在 resolve_expression 解析过程中未对聚合参数进行充分检查 别名部分可直接注入SQL代码 修复方案 严格验证annotate/aggregate/extra的kwargs参数 对列别名进行转义处理 总结与防御建议 漏洞共性 都涉及Django ORM中参数处理不严谨 都允许通过精心构造的参数注入SQL代码 都影响多个Django版本 防御措施 及时更新 :保持Django版本为最新安全版本 输入验证 : 对所有用户提供的参数进行严格验证 使用Django提供的安全函数(如Value)处理参数 最小权限原则 :数据库连接使用最小必要权限 安全编码实践 : 避免直接拼接用户输入到查询中 使用参数化查询 对特殊字符进行转义 开发者检查清单 检查项目中是否使用了受影响版本的Django 审查代码中是否直接使用用户输入作为查询参数 确保所有动态查询都使用Django的安全机制处理 对关键业务功能进行安全测试 通过深入理解这些漏洞的原理和修复方案,开发者可以更好地编写安全的Django应用程序,避免类似的SQL注入风险。