SQL注入原理是将用户可控输入直接拼接进SQL语句,使特殊字符被解析为代码而非数据;修复核心是使用参数化查询,禁用多语句执行,并对非值类动态内容(如表名、排序字段)实施白名单校验。

直接拼接源数据进目标 SQL 语句,就是把用户可控输入当代码执行——只要字段值含 '、;、UNION 或注释符,就可能触发注入。修复核心不是“过滤”,而是让数据彻底失去执行能力。
用参数化查询替代字符串拼接(所有数据库驱动都支持)
迁移工具里常见写法是:"INSERT INTO users (name) VALUES ('" + row.name + "');"。这种拼接方式无论加多少正则过滤或转义,都挡不住绕过。必须改用驱动原生的参数占位机制。
- MySQL/PostgreSQL(如 Python 的
psycopg2或pymysql):用%s占位,传参走cursor.execute(sql, params),数据库引擎会把params当纯数据绑定,不参与语法解析 - SQL Server(
pyodbc):用?占位,同样走execute(sql, params) - Java JDBC:必须用
PreparedStatement,statement.setString(1, row.name)才安全;Statement+executeUpdate()拼接字符串等于开门揖盗 - 注意:不同驱动对数组批量插入的支持差异大,
executemany()在 PostgreSQL 中支持元组列表,但 MySQL 的pymysql需显式展开,别硬套模板
源数据字段名/表名不能参数化?那就白名单校验
参数化只适用于值(VALUES、WHERE 条件),不适用于动态字段名、表名、排序字段等 DDL/DML 结构部分。这类内容若来自配置或映射规则,必须做白名单约束。
- 例如迁移配置中指定
"target_table": "orders_2024",需在加载时校验是否匹配正则^[a-z][a-z0-9_]{2,30}$,拒绝含.、;、空格、Unicode 控制字符的名称 - 排序字段如
ORDER BY ${sortField},只允许从预设集合["created_at", "status", "id"]中取值,不可自由输入 - 避免用
str.replace("'", "''")或addslashes()处理标识符——这些函数不解决语法结构污染问题,且易被 Unicode 归一化绕过
禁用多语句执行(尤其 MySQL)
很多迁移工具为图省事开启 allowMultiQueries=true(MySQL JDBC)或默认启用多语句(某些 CLI 工具)。这会让 id=1; DROP TABLE logs; 这类输入直接执行第二条语句,参数化也拦不住。
- MySQL 连接串中显式关闭:
?allowMultiQueries=false - PostgreSQL 默认不支持多语句,但若用
psql -c批量执行 SQL 文件,需确保文件内容不含分号分隔的多个命令 - 检查工具日志:如果某次迁移失败报错信息里出现
ERROR 1064 (42000)后还继续执行下一条,说明多语句未禁用
真正难处理的是嵌套场景:比如源数据本身是 JSON 字符串,而目标字段类型是 PostgreSQL 的 JSONB,有人会先 json.dumps() 再拼进 SQL——这又退回了字符串拼接。此时必须用驱动支持的原生 JSON 类型绑定(如 psycopg2.extras.Json),而不是靠 Python 序列化后塞进去。


















