必须使用数据库驱动原生支持的参数化查询机制,因str.format()或%拼接发生在python层,数据库无法区分代码与数据,' or 1=1 --等payload可直接构造恶意sql;sqlite3用?,psycopg2用%s,字段名/表名等结构元素须白名单校验。

SQL注入风险不能靠“注意拼接”来规避,必须用数据库驱动原生支持的参数化查询机制,否则任何字符串处理逻辑都可能被绕过。
为什么 str.format() 或 % 拼接永远不安全
这类操作发生在 Python 层,数据库驱动完全无法识别哪些是值、哪些是 SQL 结构。攻击者只要在用户输入中插入 ' OR 1=1 -- 这类 payload,就能让拼接后的语句变成完整可执行的恶意 SQL。
- 即使对单引号做
.replace("'", "''"),也防不住基于布尔盲注或时间盲注的绕过 -
sqlite3的execute("SELECT * FROM users WHERE name = '" + name + "'")是典型高危写法 - ORM 如 SQLAlchemy 如果用了
text()+ 字符串插值,同样失效
sqlite3 和 psycopg2 的参数占位符语法差异
不同驱动对参数化查询的占位符要求严格,混用会导致 ProgrammingError 或静默失败(如把参数当字面量)。
-
sqlite3只认?(问号)位置占位:cursor.execute("SELECT * FROM t WHERE id = ?", (user_id,)) -
psycopg2只认%s(注意不是 Python 的字符串格式化):cursor.execute("SELECT * FROM t WHERE id = %s", (user_id,)) - 绝不能在
psycopg2中写%d或{id},会触发类型错误或 SQL 解析失败
哪些场景容易漏掉参数化,尤其在动态条件构造时
WHERE 子句字段名、表名、ORDER BY 字段、LIMIT 数值——这些都不能用参数化,但开发者常误以为能塞进 %s 里。
- 字段名/表名必须白名单校验后硬编码,或用
sql.SQL()+sql.Identifier()(psycopg2.sql) -
LIMIT后的数字需转为 int 后直接拼入 SQL(因驱动不支持该位置参数化),但必须先做范围检查:if not (0 - 多个可选 WHERE 条件建议用列表累积参数,避免空条件导致 SQL 语法错误:
where_parts = []; params = [],再" AND ".join(where_parts)
真正难的不是写对一个 execute(),而是让整个项目里所有数据库交互路径都走同一套受控的参数化封装——比如统一用 DAO 类方法接收 dict 参数,内部校验键名、构建 WHERE 子句、调用带 ? 或 %s 的 execute。漏掉任意一个分支,风险就还在。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











