强类型绑定本身不防sql注入,仅确保数据结构可控;真正起防护作用的是后续配合参数化查询,使用户输入与sql语义隔离,二者缺一不可。

反序列化后做强类型绑定,本身不防SQL注入,但它是防止注入的关键前置动作。真正起防护作用的是后续对绑定后字段的使用方式——如果仍用字符串拼接构造 SQL,强类型绑定毫无意义;只有配合参数化查询,它才构成完整防线。
为什么强类型绑定不能直接防SQL注入
强类型绑定(如 Spring 的 @RequestBody User user、Jackson 的 ObjectMapper.readValue(json, User.class))只解决「把 JSON 字符串转成 Java/Go/PHP 对象」这件事。它能校验字段名、类型、非空等,但不会过滤或转义内容本身。
比如:{"name": "admin'; DROP TABLE users; -- "} 反序列化后得到一个 User.name 字段值仍是那个恶意字符串。若你随后写:"SELECT * FROM users WHERE name = '" + user.getName() + "'",照样中招。
常见错误现象:
- 接口返回 500 或数据库报错,但日志里看到执行了
DROP、UNION SELECT等语句 - 前端传
{"id": "1 OR 1=1"},后端查出全表数据 - 强类型校验通过了,但 SQL 执行异常或结果不符合预期
强类型绑定必须搭配参数化查询才有效
绑定只是让数据「结构可控」,参数化查询才是让数据「语义隔离」。两者缺一不可。
正确做法示例(Java + MyBatis):
@Select("SELECT * FROM users WHERE id = #{id} AND status = #{status}")
User selectByIdAndStatus(@Param("id") Long id, @Param("status") String status);
关键点:
使用 JSON Schema 验证 JSON 数据,从示例 JSON 生成 schema,并将其转换为 TypeScript 接口、Python 数据类或 Markdown 文档。
-
#{id}是预编译占位符,MyBatis 自动转为?并调用PreparedStatement.setLong() - 即使
user.getId()是1 OR 1=1,它也只会被当作整数 1 处理(类型不匹配时抛异常,而非拼进 SQL) - 字符串字段同理:
#{name}会走setString(),单引号、分号、注释符全部失去 SQL 语法意义
JSON 深层嵌套或动态字段怎么办
强类型绑定天然适合固定结构。遇到 content: {"custom_field": "xxx"} 这类 JSONB 或动态字段,不能靠绑定防注入——因为字段名和路径本身来自用户输入。
此时必须放弃「直接拼接 JSON 路径到 SQL」的做法。例如 PostgreSQL 中禁止这样写:
WHERE content->>'" + userInputPath + "' = '" + userInputValue + "'"
替代方案:
- 对允许的 JSON 路径做白名单限制(如只允许
["title", "author", "tags"]) - 用函数参数化路径:PostgreSQL 支持
jsonb_extract_path_text(content, VARIADIC string_to_array(?, '.')),其中?是用户输入的路径字符串,由驱动安全传入 - Go 中可用
pgx.QueryRow(ctx, "SELECT ... WHERE data->>$1 = $2", path, value),$1和$2都是参数化位置
最容易被忽略的环节:JSON 中的数字/布尔字段也得走参数化
很多人以为只有字符串要防,其实数字、布尔、null 同样危险。比如:
前端传:{"limit": "10; DROP TABLE logs;"},后端若写:"LIMIT " + req.getLimit(),就完蛋。
正确姿势:
- 所有从 JSON 解析出的字段,无论类型,只要进 SQL,就必须进
PreparedStatement/#{}/$1占位符 - 不要用
toString()或String.valueOf()再拼 SQL —— 这等于绕过所有防护 - ORM 如 Hibernate、SQLAlchemy 默认对所有映射字段使用参数化,但手动写原生 SQL 时,必须自己确保每个变量都用参数传入
复杂点在于:强类型绑定和参数化查询是两个独立步骤,中间夹着业务逻辑。一旦在 service 层做了字符串拼接,前面的绑定就白做了。防注入不是加个注解就能一劳永逸的事。










