Tortoise ORM默认参数化查询可杜绝SQL注入,但需禁用raw SQL拼接、校验动态字段名、仅通过params传参;绕过查询接口即失效防护。

只要不用 raw SQL 拼接字符串,Tortoise ORM 本身就能杜绝 SQL 注入。 它所有查询方法(.filter()、.get()、.all() 等)默认走参数化查询,底层不拼接用户输入到 SQL 字符串里。
为什么 .filter(name="xxx") 是安全的
Tortoise 将字段名和值分离处理:字段名(如 name)来自模型定义(可信),值(如 "xxx")被绑定为预编译参数,不会进入 SQL 文本。即使传入 "admin' OR '1'='1" 这类恶意字符串,最终执行的仍是类似 WHERE name = ? 的安全语句。
常见错误场景包括:
- 手动拼接
f"SELECT * FROM user WHERE name = '{name}'"—— 绝对禁止 - 用
.raw()执行原始 SQL 时直接插值 —— 即使用了.raw(),也必须用**params或params=传参 - 把用户输入当字段名使用,比如
.filter(**{user_input_field: value})—— 字段名未校验,可能绕过模型约束
.raw() 怎么用才不踩坑
只有极少数场景需要 .raw()(如复杂窗口函数、数据库特有语法)。此时必须遵守两条铁律:
- SQL 模板中所有动态值必须用
{name}占位,且只通过params=传入字典 - 字段名、表名等 SQL 结构部分,绝不能由用户控制;若必须动态,需白名单校验或硬编码映射
正确示例:await User.raw("SELECT * FROM user WHERE status = {status} AND age > {min_age}", params={"status": "active", "min_age": 18})
FastAPI + Flask 混合部署最佳实践,解决路由定义、API 代理等常见问题,适用于同时运行 FastAPI API 与 Flask 前端的场景。
错误示例:await User.raw(f"SELECT * FROM user WHERE name = '{name}'") —— 直接字符串插值,高危
软删除、条件更新这些操作是否安全
是安全的。.filter(...).update(...) 和 .filter(...).delete() 内部仍走参数化流程。例如:await User.filter(id=user_id).update(is_deleted=True)
生成的 SQL 是 UPDATE user SET is_deleted = ? WHERE id = ?,两个问号都绑定参数。
但注意:exclude_unset=True 是 Pydantic 行为,不影响 SQL 安全性;真正要防的是把用户传来的字段名/操作符(如 __gt、__in)未经限制就透传给 .filter()。建议对过滤字段做白名单限制,比如只允许 ["name", "email", "status"] 出现在 .filter(**allowed_filters) 中。
最容易被忽略的一点:Tortoise 的安全性依赖于你**不绕过它的查询接口**。一旦用 .raw()、.execute_query() 或直接调驱动连接,就回到了手写 SQL 的风险区——这时候 ORM 的防护就失效了。
大量免费API接口:立即使用
涵盖生活服务API、金融科技API、企业工商API、等相关的API接口服务。免费API接口可安全、合规地连接上下游,为数据API应用能力赋能!










