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

Python怎么防SQL注入_ORM查询参数化与安全过滤技巧

filter_by() 更安全,因其仅支持字段名等值匹配、无法传入表达式;filter() 功能强但需确保所有参数来自可信源或已清洗,误用仍可引入风险。 SQLAlchemy 的
filter()
和
filter_by()
哪个更安全? 两者本身都默认参数化,不会直接拼接 SQL,但用法不当照样引入风险。关键不在函数名,而在你传进去的是什么。 常见错误现象:
filter(User.name == request.args.get('name'))
看似正常,但如果前端传入
"admin' -- "
,而你没做任何校验或类型约束,ORM 仍会原样当字符串值处理——这本身不危险;但若后续有人把
request.args.get('name')
错误地塞进
text()
或
execute()
,就彻底绕过防护了。
filter_by()
只支持等值匹配,键必须是模型字段名,不能传表达式,相对更“傻瓜”,适合简单场景
filter()
支持复杂表达式(如
User.age > 18
),但要求所有值都来自可信来源或已清洗;别把原始请求参数直接丢进
like()
或
in_()
而不做长度/字符集限制 如果字段名本身来自用户输入(比如动态排序字段),必须白名单校验,绝不能直接拼进
getattr(User, field_name)
Django ORM 的
extra()
和
raw()
是不是高危操作? 是。这两个方法明确绕过查询构建器,直接接触 SQL 字符串,哪怕只拼一个变量,也等于打开注入大门。 使用场景:仅限极少数无法用 QuerySet 表达的复杂聚合、数据库特有函数调用,且必须确保所有外部输入都经过严格过滤。 立即学习 “ Python免费学习笔记(深入) ”;
extra()
中的
where
或
params
参数,如果
params
是字典,值会被参数化;但
tables
、
where
字符串里的字段名/表名绝不允许来自用户输入
raw()
的 SQL 字符串里,任何用户输入都必须先通过
connection.cursor().mogrify()
模拟绑定,或改用
cursor.execute(sql, params)
形式——但更推荐直接放弃
raw()
,用
annotate()
+
F()
+ 数据库函数替代 一个典型坑:
Book.objects.raw("SELECT * FROM book WHERE title LIKE '%" + user_input + "%'")
—— 这行代码不管用什么 ORM,都等于裸奔 手写原生 SQL 时,
psycopg2
和
sqlite3
的参数占位符写法有什么区别? 不只是写法不同,不统一用法会导致参数未被绑定,变成字符串拼接。 Python 3.14.3 微软官方的 Python 扩展,是 VS Code 安装量最高的扩展(209M+)。集成 IntelliSense(通过 Pylance)、调试(通过 Python Debugger)、代码检查、格式化、重构和单元测试等功能。支持 Jupyter Notebook、虚拟环境管理和多 Python 版本切换。 下载 性能影响:占位符解析由驱动层完成,和硬拼字符串相比几乎没有开销;但错用会引发 SQL 解析失败或隐式类型转换问题。
psycopg2
必须用
%s
(注意是字面量
%s
,不是 Python 的
%
格式化),参数传 tuple 或 dict:
cursor.execute("SELECT * FROM user WHERE id = %s", (user_id,))
sqlite3
支持
?
、
:name
、
:1
三种,但不支持
%s
;用
%s
会直接报错或静默拼接:
cursor.execute("SELECT * FROM user WHERE name = ?", (name,))
千万别混用:
"WHERE id = %s".format(id)
或
f"WHERE id = {id}"
—— 这些在任何驱动下都是高危操作 为什么对用户输入做
strip()
或正则替换不能代替参数化? 因为过滤只是辅助手段,不是安全边界。SQL 注入的本质是语义混淆,不是字符黑名单能覆盖的。 容易踩的坑:看到别人删掉了单引号、分号就以为万事大吉,结果遇到宽字节、编码绕过、注释符嵌套、或数据库特有的 escape 序列(如 MySQL 的
\'
)依然中招。 正则替换可能漏掉 Unicode 等价字符(如全角单引号、零宽空格),或误杀合法内容(比如用户名含撇号 “O’Neill”)
strip()
对
" admin' OR '1'='1"
这类 payload 完全无效 唯一可靠的防线只有参数化:让数据和 SQL 结构彻底分离,数据库引擎自己负责转义和类型绑定 参数化不是“加个括号就完事”的动作,而是贯穿查询构建全程的约束意识——从最外层的 ORM 方法选择,到内层 raw SQL 的占位符写法,再到动态字段名的白名单控制,每一步偏离都会让防护失效。

相关文章