参数绑定本身不能阻止SQL注入,只有正确使用才能;表名、字段名等SQL结构部分不可参数化,必须白名单校验,且不同数据库驱动占位符(?、%s、$1等)不可混用,否则参数不绑定或报错。

参数绑定本身不能阻止SQL注入——只有正确使用它才能。关键不是“用了没”,而是“怎么用”。
为什么 execute 传元组却还是被注入?
常见错觉:只要用了 ? 或 %s,就万事大吉。实际中大量漏洞仍发生在参数化查询里,根源是把不该参数化的部分也塞进了绑定位置。
- 表名、字段名、排序方向(
ASC/DESC)、IN子句长度等 SQL 结构部分,**不能**用参数绑定,数据库驱动不支持,强行传进去只会报错或静默失败 - 错误示例:
cursor.execute("SELECT * FROM ? WHERE id = ?", ("users", 123))→ 运行时报sqlite3.OperationalError: near "?": syntax error - 这类结构必须靠白名单校验或硬编码控制,比如
table_name in ("users", "orders"),而不是拼接或反射获取
sqlite3 里 ? 和 :name 占位符能混用吗?
不能。SQLite 的 execute 方法只接受一种风格的参数,混用会导致 sqlite3.ProgrammingError: Incorrect number of bindings supplied。
-
?风格:参数必须是序列(tuple或list),顺序严格对应 -
:name风格:参数必须是dict,键名需与 SQL 中的命名占位符完全一致 - 错误写法:
cursor.execute("SELECT * FROM t WHERE a = ? AND b = :x", (1, {"x": 2}))→ 类型不匹配,直接崩 - 正确写法二选一:
cursor.execute("...", (1, 2))或cursor.execute("...", {"x": 1, "y": 2})
MySQL / PostgreSQL 驱动的占位符为什么不是 ??
不同数据库驱动约定不同,硬记 ? 会翻车。用错占位符不会报语法错,但参数根本不会绑定,输入直接变成字面量,等于裸奔。
-
mysql-connector-python和pymysql用%s(注意是字符串格式符,不是类型) -
psycopg2(PostgreSQL)用%s,但底层是$1,$2,用户无需写 - 错误示例:
cursor.execute("SELECT * FROM t WHERE x = ?", (val,))在 pymysql 中不会报错,但?被当作文本字面量处理,val完全不生效 - 查文档比猜可靠:运行
print(cursor.__class__.__module__)确认驱动,再查其execute文档里的 placeholder 说明
最容易被忽略的点:参数绑定只保数据安全,不保逻辑安全。一个合法的数字参数 123 绑定进 WHERE id = ? 是安全的,但如果这个 id 来自 URL 路径且未做权限校验,照样可能越权读取他人数据——防注入只是基础防线,不是万能盾。

















