sqlite3防sql注入唯一可靠方式是正确使用?或:name占位符配合元组/字典传参,禁用字符串拼接、%s、f-string及动态表名列名;单参数须写为(value,)或[value],结构元素需白名单校验。

只要用对 execute() 的参数传法,sqlite3 本身就能防住绝大多数 SQL 注入;但一旦写成字符串拼接或混用占位符,防护就立刻失效。
sqlite3 只认 ? 和 :name,其他占位符全是无效的
sqlite3 不支持 %s、${var} 或 f-string 插入——这些都会被当作普通字符串字面量处理,不触发参数绑定。比如:
-
cursor.execute("SELECT * FROM users WHERE id = %s", (123,)):%s被当成文本,实际执行的是WHERE id = '%%s',查询永远为空 -
cursor.execute(f"SELECT * FROM users WHERE name = '{name}'"):直接拼接,name里塞' OR 1=1 --就能绕过验证 - 正确写法只有两种:
?(位置参数)或:name(命名参数),且必须配对传参
传参必须是元组或字典,不能是单个值或列表
常见错误是把单个变量直接传进去,或者误用列表,导致类型不匹配而降级为字符串拼接:
-
cursor.execute("SELECT * FROM users WHERE id = ?", 123):报TypeError,因为第二个参数必须是序列(元组/列表/字典) -
cursor.execute("SELECT * FROM users WHERE id = ?", [123]):虽然能运行,但 sqlite3 对列表的支持不稳定,某些版本会静默失败或行为异常 - 安全写法只有:
(123,)(注意末尾逗号)或{"id": 123},再配合WHERE id = ?或WHERE id = :id
表名、字段名、ORDER BY 这些根本不能参数化
数据库语法不允许 SELECT ? FROM ? 或 ORDER BY ?,这类写法直接报 sqlite3.OperationalError。它们必须靠白名单控制:
- 动态表名:用硬编码映射,如
table_map = {"user": "users_v2", "log": "logs_2026"},用户只输 key,查表后拼进 SQL - 排序字段:限定在
allowed_sort = {"id", "name", "updated_at"}内,不在其中就 fallback 到"id" - 限制数量:
limit = max(1, min(100, int(request.args.get("limit", "20")))),再拼进LIMIT {limit}
最易忽略的一点是:ORM 或框架里的 raw()、text()、extra() 接口,一旦用了,就等于退回手写 SQL 阶段——此时占位符规则和校验逻辑全得自己扛,不能指望框架兜底。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











