细数Django框架核心历史SQL注入漏洞(下)
字数 2026 2025-08-06 18:07:49
Django框架核心历史SQL注入漏洞分析与防护指南
概述
本文详细分析Django框架历史上出现的三个核心SQL注入漏洞(CVE-2022-28346、CVE-2022-28347、CVE-2022-34265),包括漏洞原理、影响范围、利用方式及修复方案。这些漏洞涉及Django的QuerySet API关键函数,在特定配置下可能导致SQL注入风险。
CVE-2022-28346 - annotate/aggregate/extra函数注入漏洞
漏洞描述
Django在2022年发布的安全更新修复了QuerySet的annotate()、aggregate()和extra()函数中存在的SQL注入漏洞。攻击者可通过精心构造的别名参数注入恶意SQL代码。
影响版本
- Django 2.2.x < 2.2.28
- Django 3.2.x < 3.2.13
- Django 4.0.x < 4.0.4
- 需使用
annotate、aggregate或extra方法且参数可控
漏洞分析
-
漏洞根源:
add_annotation和add_extra函数未对参数进行充分过滤- 用户可控参数直接成为
self.annotations的键 - 在
resolve_ref函数中被取出并直接使用
-
关键代码路径:
django/db/models/query.py中的aggregate方法- 参数经过
_validate_values_are_expressions处理但未过滤 - 最终在SQL解析阶段被直接拼接
-
修复方案:
- 对
alias参数添加正则过滤 - 限制特殊字符在注解别名中的使用
- 对
漏洞复现
-
环境配置:
# views.py from django.shortcuts import render, HttpResponse from .models import Collection from django.db.models import Count def vuln(request): query = request.GET.get('q') qs = Collection.objects.annotate(**{query: Count("name")}) return HttpResponse(qs) -
利用Payload:
http://127.0.0.1:8000/vuln/?q=aaaaa%22
CVE-2022-28347 - explain()函数注入漏洞
漏洞描述
Django修复了QuerySet的explain()函数中存在的SQL注入漏洞,攻击者可通过控制explain选项注入恶意SQL。
影响版本
- Django 2.2.x < 2.2.28
- Django 3.2.x < 3.2.13
- Django 4.0.x < 4.0.4
- 需使用
explain方法且参数可控
漏洞分析
-
漏洞根源:
explain_query_prefix处理用户提供的options时未充分过滤- PostgreSQL后端直接将选项键名拼接到SQL语句
-
关键代码路径:
django/db/models/sql/compiler.py中的explain处理django/db/backends/postgresql/operations.py的explain_query_prefix方法- 选项键名直接写入SQL前缀
-
修复方案:
- 实现options内容过滤
- 建立选项键名白名单机制
漏洞复现
-
环境配置:
# views.py from django.shortcuts import render, HttpResponse from .models import Collection import json def vuln(request): query = request.GET.get('q') query = json.loads(query) qs = Collection.objects.filter(name="tom").explain(**query) return HttpResponse(qs) -
利用Payload:
http://127.0.0.1:8000/vuln/?q={"ANALYZE true)":"aaa"}
CVE-2022-34265 - Trunc/Extract函数注入漏洞
漏洞描述
Django修复了Trunc()和Extract()函数中存在的SQL注入漏洞,攻击者可通过控制查询参数注入恶意SQL。
影响版本
- Django 3.2.x < 3.2.14
- Django 4.0.x < 4.0.6
- 需使用
Trunc()或Extract()方法且参数可控
漏洞分析
-
漏洞根源:
Extract和Trunc类的as_sql方法未过滤lookup_name参数- 参数直接传递到
datetime_extract_sql和datetime_trunc_sql函数 - 最终在else分支中直接拼接SQL
-
关键代码路径:
Extract.as_sql方法datetime_extract_sql和date_extract_sql函数lookup_type参数直接拼接
-
修复方案:
- 为
Extract和Trunc类的as_sql方法添加正则过滤 - 限制特殊字符在查询参数中的使用
- 为
漏洞复现
- 利用Payload:
http://127.0.0.1:8000/?date=aaa%27
防护建议
-
通用防护措施:
- 及时升级到Django安全版本
- 对所有用户输入进行严格验证和过滤
- 使用Django ORM提供的参数化查询
-
针对特定漏洞:
- 避免直接使用用户输入作为注解别名
- 限制explain选项的来源
- 验证Trunc/Extract函数的参数
-
安全开发实践:
- 遵循最小权限原则
- 实施输入验证和输出编码
- 定期进行安全审计和代码审查
参考资源
- Django官方安全公告
- CVE详细描述:
- Django GitHub修复提交记录
通过深入理解这些漏洞的原理和利用方式,开发者可以更好地保护Django应用免受SQL注入攻击,同时提高整体应用安全性。