Django ORM vs 原生SQL安全:用户输入查询是否必须用ORM?自定义函数可行吗?
问题背景与疑问
我的Django项目包含大量数据库查询,既有复杂查询也有无条件逻辑的基础SELECT查询。目前我使用sqlite3模块而非Django ORM来管理数据库,已知原生SQL查询存在安全缺陷,比如处理用户输入时易遭SQL注入攻击。
我的问题是:处理含用户输入的查询时,是否必须使用Django ORM?还是可以使用通用函数移除潜在恶意字符(如(,' -, *, ;))来替代?
示例代码
清理函数
def remove_characters(string:str): characters = ["'", ";", "-", "*"] for char in characters: if char in string: string = string.replace(char, "") return string
存在风险的查询示例
username = "logan9997" password = "x' or 'x' = 'x" def check_login(self, username, password): sql = f""" SELECT * FROM App_user WHERE username = '{remove_character(username)}' AND password = '{remove_character(password)}' """
若不使用remove_characters函数,攻击者可通过未 sanitized 的输入非法获取他人账户权限。我想知道:该函数能否彻底消除SQL注入威胁?处理含用户输入的查询时,使用ORM是否更合理?
回答
你的清理函数无法彻底消除SQL注入风险
这种字符过滤的黑名单思路漏洞百出:
- 攻击者可轻松绕过过滤:比如输入
x'' or ''x'' = ''x,过滤后会变成x or x = x,照样能构造注入逻辑; - 不同数据库注入手法差异大:SQLite支持的部分注入语法不需要你过滤的字符,依然能执行恶意操作;
- 破坏合法输入:如果用户的用户名/密码本身包含
-或*(如user-name),函数会直接删除这些字符,导致正常用户无法登录。
不一定要用Django ORM,但绝对不能用字符串拼接+黑名单过滤
如果不想用Django ORM,正确方案是使用参数化查询——这是所有数据库驱动都支持的安全机制,sqlite3模块本身就支持:
def check_login(self, username, password): sql = """ SELECT * FROM App_user WHERE username = ? AND password = ? """ # 通过cursor.execute的参数传入方式,而非字符串拼接 cursor.execute(sql, (username, password))
参数化查询会由数据库驱动自动处理输入转义,从根源上避免SQL注入,比任何手动过滤都可靠。
使用Django ORM是更合理的选择
除了自动防注入,ORM还有诸多优势:
- 多数据库适配:后续从SQLite切换到MySQL/PostgreSQL时,无需修改大量SQL代码;
- 减少重复代码:ORM的查询API能简化基础CRUD操作,避免手写重复SQL;
- 内置安全机制:除防注入外,还会处理字段类型校验等其他安全问题;
- 更高可维护性:ORM代码可读性更强,团队协作成本更低。
如果是极复杂的查询,ORM无法覆盖时,可以用Django的raw()方法执行原生SQL,但依然要配合参数化,而非字符串拼接:
from django.db import connection def complex_query(user_id): with connection.cursor() as cursor: cursor.execute( "SELECT * FROM App_user WHERE id = %s AND created_at > %s", [user_id, "2024-01-01"] ) results = cursor.fetchall()
内容的提问来源于stack exchange,提问作者logan_9997
相关产品推荐
相关产品推荐

