django 5 orm 默认防值层面 sql 注入,但动态字段名、raw()、extra()、rawsql 等场景需白名单校验与参数化;字段名、排序、聚合等结构部分无自动防护,必须手动校验。

Django 5 的 ORM 默认能防 MySQL(及其他后端)的值层面 SQL 注入,但只要用到 raw()、extra()、RawSQL 或动态字段名,防护就立刻失效——这不是 Django 的 bug,而是设计使然:它只参数化“值”,不校验“结构”。
filter() 动态字段名必须白名单校验
用户输入的字段名(比如搜索参数 field=title)如果直接塞进 filter(**{field: value}),Django 不会转义 key,攻击者可传 is_staff__gt、_meta.model_name 甚至 password__contains 触发越权或信息泄露。
- 先硬性限制可用字段:
if field not in ["title", "author__name", "status", "created_at__year"]:然后抛ValueError - 再用
MyModel._meta.get_field(field)确认字段真实存在且非计算属性(如@property) - 别用
Q("title__icontains = '{}'".format(q))拼字符串;改用Q(**{f"{field}__icontains": q}),前提是field已过白名单
raw() 和 extra() 必须严格用 params=[...] 且只认 %s
raw() 和 extra() 完全跳过 ORM 编译器,拼接即失守。PostgreSQL 支持 %(name)s,但 MySQL 和 SQLite 不支持,混用会报错或静默失败。
python-docx Skill功能概述python-docx Skill是一项面向实际任务的技能,主要用于本Skill提供使用python-docx生成专业Word文档的标准方法和最佳实践;生成安全服务方案文档;核心要点生成技术架构设计文档;生成任何需要专业排版的Word文档;核心库 : python-docx;使用与执行辅助库 : docx.shared , docx.enum , docx.oxml.ns;标准代码模板;1. 文档初始化;2. 字体设置(必须!它将相关步骤、工具调用和结果整理方式集
- 错误:
User.objects.raw(f"SELECT * FROM auth_user WHERE username = '{u}'")—— 字符串插值直接开门 - 正确:
User.objects.raw("SELECT * FROM auth_user WHERE username = %s", params=[u])——params必须是列表或元组 -
extra(where=["status = %s"], params=[u])是安全写法;但extra(where=[f"status = '{u}'"])等同裸写 SQL -
extra()的params参数在 Django 中实际被忽略,真正起作用的是 where 字符串里的%s占位符 + 外层params=传参
RawSQL 在 annotate() 或 filter() 中需手动参数化
RawSQL 表达式本身不继承外层 QuerySet 的参数绑定逻辑,params= 只绑定它自己 SQL 内的占位符。漏掉这步,LIKE 里的 % 和 _ 就变成通配符,不是注入,但属严重逻辑漏洞。
- 错误:
annotate(score=RawSQL(f"CASE WHEN title LIKE '%{search}%' THEN 1 ELSE 0 END")) - 正确:
RawSQL("CASE WHEN title LIKE %s THEN 1 ELSE 0 END", params=[f"%{search}%"]) - 更稳妥:
Case(When(title__icontains=search, then=1), output_field=IntegerField())—— ORM 原生表达式自动处理转义、索引和数据库兼容性 - 若必须用原生
LIKE,调用connection.ops.prep_for_like_query(search)手动转义通配符
cursor.execute() 绕过 ORM 时完全依赖底层驱动
直接用 connection.cursor() 时,Django 不提供任何防护,安全性全靠你和数据库驱动。MySQLdb、PyMySQL、mysqlclient 都支持 %s 位置参数,但不支持字符串格式化。
- 错误:
cursor.execute("SELECT * FROM user WHERE id = " + str(user_id))或f"WHERE id = {user_id}" - 正确:
cursor.execute("SELECT * FROM user WHERE id = %s", [user_id])—— 注意是列表,不是元组(虽多数驱动也认元组,但列表更稳) - 批量操作慎用
executemany(),确保每条语句都走参数化,不要把用户输入塞进 SQL 模板里再循环
最常被忽略的不是“怎么写安全代码”,而是误以为“用了 ORM 就万事大吉”。字段名、排序字段(order_by(request.GET.get('o')))、聚合函数名、全文检索配置(__search)、正则模式(__regex)——这些结构部分,Django 一律不管。白名单校验不是可选项,是必选项。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!










