跳转到主内容
新派编程网 - 新潮编程理念,全新技术课堂!

Django框架中如何防范SQL注入_依赖内置的对象关系映射ORM

Django ORM 能防 SQL 注入是因为其通过参数化查询绑定用户输入的值,而非拼接字符串;但字段名、表名等结构元素需手动白名单校验,否则仍存在风险。 直接用 Django ORM 就能防 SQL 注入,前提是别绕过它去拼接字符串。 只要你坚持用
filter()
、
get()
、
exclude()
这类方法传参,Django 会在底层自动做参数化处理——用户输入永远不会被当作 SQL 代码执行。 为什么 ORM 能天然防注入 Django ORM 不是把 Python 表达式转成 SQL 字符串再执行,而是构建查询表达式树,最后由数据库驱动统一绑定参数。这意味着
username
字段的值永远走的是
WHERE username = %s
+ 参数元组的方式,和手写
cursor.execute("SELECT ... WHERE name = %s", [name])
是同一套安全机制。 常见错误现象:有人看到
User.objects.filter(username=request.GET.get('u'))
觉得“好像没做验证”,其实完全没问题;但一旦改成
raw("SELECT * FROM auth_user WHERE username = '{}'".format(u))
,就立刻掉进坑里。 ORM 方法(如
filter()
)只接受字段名作为关键字参数名,值一律走参数绑定 字段名本身不能动态传入(比如
filter(**{field_name: value})
),否则需额外校验字段白名单 像
order_by()
、
values_list()
这类接收字段名字符串的方法,不涉及用户值代入,但字段名若来自请求,仍要限制范围 哪些 ORM 写法看似安全实则危险 不是所有带
objects
的调用都免疫注入。以下操作会绕过 ORM 的参数化保护:
extra()
中的
tables
、
where
、
params
若混入未过滤的用户输入(如
extra(where=["status = '{}'".format(user_input)])
)
raw()
查询中用
%
或
.format()
拼接 SQL,哪怕只拼字段名或表名
annotate()
或
aggregate()
里用
Func()
构造表达式时,把用户输入直接塞进
template
字符串 例如这个管理器写法就是高危的:
.extra(select={'score': "COALESCE({}, 0)".format(request.GET.get('col'))})
——
col
值若为
id); DROP TABLE auth_user; --
,就完了。 防SQL注入的php类库 防SQL注入的php类库 下载 必须手动校验的边界场景 ORM 只保护“值”,不保护“结构”。当你需要动态决定查哪个字段、按什么排序、用什么聚合函数时,就得自己把关: 对
request.GET.get('sort')
做白名单检查:
if sort not in ['id', '-name', 'email']:
才允许传给
order_by(sort)
用
getattr(MyModel, field_name, None)
确认字段真实存在且可查询,再用于
values(field_name)
避免在
Q()
对象中拼接字符串条件,改用字典解包:
Q(**{field_name + '__icontains': keyword})
,前提是
field_name
已校验 性能影响几乎为零,但漏掉校验字段名,等于在防火墙上凿了个洞——ORM 的防护层就失效了。 真正容易被忽略的点是:ORM 防得住值,防不住字段名、表名、函数名这些 SQL 结构元素。只要用户输入参与了 SQL 的“骨架”生成,就必须手动白名单或映射,而不是依赖 ORM 自动兜底。

相关文章