SQL注入防护核心是参数绑定而非Python版本,各数据库驱动占位符语法严格不同,单参数须用元组或列表,text()/raw()需显式命名参数,表名列名等动态标识符必须白名单校验。

直接用 f""、% 或 .format() 拼接用户输入到 SQL 字符串里,就是给 SQL 注入开后门。Python 3.12 本身不改变这一规则——安全与否,只取决于你是否让数据库驱动做参数绑定,而不是 Python 版本。
psycopg2 / MySQL / SQLite 驱动的占位符必须严格匹配
不同驱动对占位符语法有硬性要求,混用等于白写:
-
psycopg2(PostgreSQL)只认%s,传?或:name会当字面量处理,不触发绑定 -
sqlite3支持?和:name,但不支持%s(哪怕你写了也不会报错,而是当成普通字符串) -
pymysql和mysql-connector-python只认%s,用?会抛ProgrammingError
错误示例:cursor.execute("SELECT * FROM users WHERE id = ?", (123,)) 在 PostgreSQL 里不会报错,但 ? 不被识别为参数,实际执行的是 WHERE id = ?,结果永远为空。
execute() 的第二个参数必须是序列,不是单个值
这是新手最常踩的坑:漏括号、少逗号、传字符串或数字本身。
- ✅ 正确:
cursor.execute("SELECT name FROM users WHERE id = %s", (123,))(注意末尾逗号) - ✅ 正确:
cursor.execute("SELECT name FROM users WHERE id = %s", [123]) - ❌ 错误:
cursor.execute("SELECT name FROM users WHERE id = %s", 123)→ 报TypeError: not all arguments converted - ❌ 错误:
cursor.execute("SELECT name FROM users WHERE id = %s", "123")→ 字符串被当元组迭代,第一个字符'1'被传入
即使只有一个参数,也必须显式构造单元素元组或列表。Python 3.12 不会帮你“智能补全”。
text() 和 raw() 不自动参数化,必须手动配 params
SQLAlchemy.text() 和 Django raw() 是安全边界断裂点——它们只是把字符串原样交给数据库,不做任何解析。
- ❌ 危险:
session.execute(text(f"SELECT * FROM logs WHERE user = '{user}'"))→ f-string 在 Python 层已拼完,完全绕过绑定 - ❌ 危险:
session.execute(text("SELECT * FROM logs WHERE user = %s"), [user])→%s是 psycopg2 语法,但text()默认走 SQLAlchemy 统一编译器,可能不识别 - ✅ 安全:
session.execute(text("SELECT * FROM logs WHERE user = :user"), {"user": user})→ 命名占位符 + 字典参数,跨驱动兼容
关键:占位符形式(:name)和参数类型(字典)必须同时满足,缺一不可。用元组传参给 text() 会按位置匹配,极易错位。
表名、列名、ORDER BY 字段不能参数化,必须白名单校验
这不是 Python 或驱动的限制,是 SQL 协议层硬约束。数据库在解析 SQL 阶段就要确定执行计划,而参数绑定发生在执行阶段。
- ❌ 不可能:
cursor.execute("SELECT * FROM %s WHERE id = %s", ("users", 123)) - ❌ 不可能:
session.execute(text("SELECT * FROM users ORDER BY :col"), {"col": "created_at"}) - ✅ 可行:
allowed_cols = {"created_at", "name", "status"}; col = request.args.get("sort", "id"); if col not in allowed_cols: raise ValueError("Invalid sort field"); cursor.execute(f"SELECT * FROM users ORDER BY {col}")
动态标识符没有“安全默认值”,必须显式定义允许范围。哪怕只开放两个字段,也要检查;否则任意字符串都可能变成 users; DROP TABLE logs--。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











