使用 Flask-SQLAlchemy 的 filter_by() 或参数化 query.filter() 最安全,原生 SQL 必须用 text() 配字典参数,禁止字符串拼接;表名列名需白名单校验,WAF 仅作补充而非替代。

直接用 User.query.filter_by() 就安全,别手写 SQL
Flask 本身不防注入,但绝大多数项目用 Flask-SQLAlchemy,只要全程走模型的查询接口,就默认启用参数化查询。比如 User.query.filter_by(username=username).first() 或 User.query.filter(User.email == email).all(),底层生成的是带绑定参数的预编译语句,用户输入进的是参数槽,不是 SQL 文本。
常见错误是看到 URL 参数就自己拼 SQL:db.session.execute(f"SELECT * FROM user WHERE id = {request.args.get('id')}")——哪怕加了 int() 转换,如果类型转换失败没拦截(比如传 id=1 OR 1=1),照样崩。
- 等值查询优先用
filter_by(),它只接受关键字参数,天然防错 - 复杂条件(
like、in_、isnull)必须用filter()配属性比较,如User.name.like(f"%{kw}%")是危险的,应改用User.name.like("%" + kw + "%")(注意:这里仍需确保kw已校验,否则%本身可能被滥用) -
get()查主键最安全,User.query.get(123)底层走主键索引+参数绑定,连字符串都绕不开
session.execute(text()) 怎么写才不漏掉漏洞
真要写原生 SQL(比如窗口函数、多表 union、JSON 字段解析),必须用 sqlalchemy.text() 加字典传参。f-string、% 格式化、.format() 全部禁止。
错误写法:session.execute(f"SELECT * FROM logs WHERE level = '{level}'");攻击者输 error'-- 就能注释掉后续条件。
立即学习“Python免费学习笔记(深入)”;
让 macOS 自动化像说话一样简单 —— 用代码控制你的 Mac,无需学习 AppleScript 系统要求 macOS 14+ (Sonoma) Python 3.9+ 需要开启:辅助功能 + 屏幕录制权限
- 占位符必须用命名风格:
:level,不能用?或%s - 第二个参数必须是字典,键名和占位符严格一致:
{"level": level} - 别用元组传参,顺序错一位就全乱;也别用
**locals(),容易把内部变量意外塞进去 - 表名、列名无法参数化,必须硬编码,或走白名单校验(如
if sort_field not in ["created_at", "score"]: abort(400))
别信“过滤单引号”这种土办法
有人写 input.replace("'", "''").replace("--", ""),以为能拦住注入——完全无效。攻击者用 0x756e696f6e2073656c656374(union select 的十六进制)、Unicode 拆分、宽字节编码都能绕过。
真正有效的防御只有一条路径:让数据库驱动在协议层就把 SQL 结构和数据分开传输。参数化查询和 ORM 正是干这事的;字符过滤只是在应用层做文本清洗,跟 SQL 解析完全不在一个层面。
- 对数字型参数,直接
int(request.args.get("page", "1")),类型不符就抛异常,比任何正则都可靠 - 对字符串字段,长度限制 + 白名单字符集(如用户名只允许字母数字下划线)比删单引号有用得多
- 所有外部输入源都要盯紧:不只是
request.args,还有request.headers.get("X-Forwarded-For")、request.cookies、甚至上传文件的filename字段
WAF 只能当最后一道防线,不能替代代码层防护
有同学装了 Flask WAF 包,以为万事大吉。但 WAF 规则靠正则匹配 payload,遇到变形编码、嵌套注释、空格绕过(UNION/**/SELECT)很容易漏。它能拦住扫描器批量试探,但防不住定制化盲注。
更关键的是:WAF 拦截后日志里只记“疑似 SQL 注入”,你根本不知道哪行代码漏了。而 ORM 或 text() 写错,本地调试时就能复现报错、看到原始 SQL、定位到具体语句。
- WAF 适合补漏,比如 legacy 代码来不及重写,或第三方 SDK 的 SQL 操作不可控
- 新功能必须从第一行代码开始按 ORM 或参数化写,WAF 不是你推迟修复的理由
- 动态字段名(如按用户选的排序字段
ORDER BY {{field}})必须白名单校验,WAF 压根没法判断这个field是不是合法列名

















