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