psycopg3防SQL注入的唯一可靠方式是严格参数化:用户输入必须作为params传入execute(),禁用f-string/str.format拼接;表名列名等标识符须用sql.Identifier+白名单校验。

psycopg3 的参数化查询是防注入的唯一可靠方式
psycopg3 默认不支持字符串拼接式 SQL 构造,也不提供类似 cursor.execute("SELECT * FROM users WHERE name = '" + name + "'") 这种危险用法的“便利性”——这不是设计疏忽,而是强制你走安全路径。只要不用 str.format()、f-string 或 + 拼接 SQL 字符串,就基本不会中招。
核心原则:所有用户可控输入(表单、URL 参数、文件内容等)必须作为参数传入 cursor.execute() 或 cursor.executemany() 的第二个参数,不能出现在 SQL 字符串里。
哪些写法会触发 SQL 注入(即使用了 psycopg3)
以下操作看似“只是拼个字符串”,但会绕过 psycopg3 的参数化机制,导致注入风险:
- 用
f"SELECT * FROM {table_name} WHERE id = %s"拼接表名、列名、ORDER BY 字段等——%s占位符对这些位置无效,psycopg3 不会转义或引号包裹它们 - 用
str.replace()或正则替换后拼进 SQL 字符串,比如"WHERE status IN (" + ",".join(["%s"] * len(statuses)) + ")"再手动.format()——这等于自己构造了可执行片段 - 把用户输入先塞进一个字典再用
**params解包进execute("...", params),但 SQL 字符串里写了%(user_input)s以外的动态部分(如%(user_input)s::jsonb中的::jsonb被用户控制)
动态表名/列名等元数据怎么办
psycopg3 不允许参数化标识符(identifier),所以 %s 不能用于表名、字段名、排序字段。此时必须白名单校验或使用 sql.Identifier() + sql.SQL() 组合。
正确做法是显式导入并构造:
from psycopg.sql import SQL, Identifier
<h1>安全:只接受预定义的表名</h1><p>allowed_tables = {"users", "orders", "products"}
if table_name not in allowed_tables:
raise ValueError("Invalid table name")</p><p>query = SQL("SELECT * FROM {} WHERE id = %s").format(Identifier(table_name))
cursor.execute(query, [user_id])
</p>
注意:Identifier() 仅做双引号包裹和转义,不解决逻辑层校验;若表名来自不可信源且未校验,仍可能指向恶意视图或系统表。
让 macOS 自动化像说话一样简单 —— 用代码控制你的 Mac,无需学习 AppleScript 系统要求 macOS 14+ (Sonoma) Python 3.9+ 需要开启:辅助功能 + 屏幕录制权限
批量插入与 executemany 的参数陷阱
executemany() 看似方便,但容易误用成“把一堆字典拼成 SQL 字符串”。它只接受二维序列(如 [(1, "a"), (2, "b")])或字典列表(键名需与 SQL 中的 %(key)s 严格匹配),且不支持嵌套结构或运行时生成占位符数量。
常见错误:
- 用
executemany("INSERT INTO t VALUES (%s, %s)", [[x] for x in data])—— 参数维度错,应为[(x,) for x in data] - 试图在循环里拼
"INSERT INTO t VALUES " + ", ".join(["%s"] * len(row))再传参 —— 占位符数量动态变化,psycopg3 不允许这种运行时构造 - 传入含
None的元组却没设字段类型,导致隐式类型推断失败(尤其 JSON/ARRAY 字段)
建议:固定字段数的批量操作优先用 executemany();字段数不固定或含复杂类型,改用 execute() 配合 sql.Composed 构造,或分批处理。
最常被忽略的一点:连接池配置中的 autocommit=False(默认)意味着每次 execute() 后必须显式 commit() 或 rollback(),否则事务挂起,不仅影响并发,还可能让带 RETURNING 的注入利用链更隐蔽。别只盯着 SQL 字符串,事务边界也是攻击面的一部分。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!










