You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.31 10:55:50