JSON解析结果必须视为不可信输入,所有值须经白名单校验并严格参数化处理,禁止字符串拼接SQL;动态字段名、JSON路径等均需双重校验,否则将导致SQL注入。

JSON字段解析后直接拼进SQL字符串,等于开门揖盗
只要把解析出来的JSON值(比如 user.get("name"))用 + 或 String.format() 塞进 SQL 字符串里,就立刻回到高危状态。哪怕你前面用了 ObjectMapper.readValue()、做了非空校验、甚至 trim 了空格,都拦不住 ' OR '1'='1 这类输入。数据库只认语法,不认“你本意是不是想查数据”。
常见错误现象:MySQLSyntaxErrorException 频发但 SQL 日志里看不出明显语法错;某次传 {"status":"active' -- "} 后查询返回全部记录;后台日志出现 UNION SELECT 或 EXTRACTVALUE 等报错注入特征。
- 所有 JSON 解析结果(
JsonNode.asText()、Map.get()、object.field)都必须视为不可信输入 - 禁止对 JSON 字段做任何“看起来安全”的假设——比如认为 status 只能是 active/inactive,就跳过参数化
- 如果 JSON 结构固定,优先用 Jackson 的
@JsonProperty+ POJO 绑定,而非泛型Map<String, Object>
MyBatis 中 JSON 字段必须用 #{},禁用 ${}
${} 是字符串替换,JSON 字段值进去就是裸奔;#{} 才走 PreparedStatement 预编译。哪怕字段名来自 JSON,只要它是值(不是表名、排序字段),就必须走 #{}。
使用场景:用户提交 {"filter":{"name":"admin","age":25}},后端解析后用于 WHERE 条件。
- 正确写法:
WHERE name = #{filter.name} AND age = #{filter.age} - 错误写法:
WHERE name = '${filter.name}'(单引号包着也无效) - 模糊查询要加
concat('%', #{keyword}, '%'),不能写成"%${keyword}%" - 如果 JSON 里嵌套了数组(如
{"ids":[1,2,3]}),需转成IN (?, ?, ?)形式,用 MyBatis 的<foreach>动态生成占位符
动态字段名(如 JSON 中的 sortField)必须白名单硬校验
JSON 里如果带 {"sort":"email DESC"} 这种字段,ORDER BY ? 会直接报错——预编译不支持结构参数。这时候不能妥协用 String.format("ORDER BY %s", sort),得靠白名单+正则双保险。
将一个或多个视频上传至YouTube。当用户想“上传到YouTube”“发YouTube”“批量上传”“upload to YouTube”“post videos to YouTube”或发布到YouTube时使用此技能。
性能影响几乎为零,但漏掉一个字符就可能被绕过。
- 定义明确白名单:
Set.of("id", "name", "email", "created_at") - 方向单独校验:
if (!"ASC".equals(dir) && !"DESC".equals(dir)) throw new IllegalArgumentException(); - 完整匹配组合:
"email DESC"必须整体在白名单中,不能只校验email部分 - 拒绝任何空白符、Unicode 分隔符、不可见字符——用
sort.trim().replaceAll("\s+", " ")规范化后再比对
JSON 路径表达式(如 JSON_EXTRACT(user_meta, '$.phone'))也要参数化
MySQL 8.0+ 和 PostgreSQL 的 JSON 函数虽支持路径字符串,但路径本身若来自用户输入(比如前端传 path: "$.settings.theme"),仍可能被构造为 "$.settings.theme' OR '1'='1" 导致注入。路径不是值,但它是执行上下文的一部分。
容易踩的坑:以为 JSON 函数自动免疫,结果在 WHERE JSON_EXTRACT(data, ?) = ? 里只对右边的值参数化,左边路径没处理。
- 路径字段必须走白名单:
if (!allowedPaths.contains(path)) throw ... - 禁止拼接路径字符串:
"$.user." + userInput是典型错误 - PostgreSQL 的
->>操作符同理,json_col ->> ?不合法,必须先校验再硬编码 - 如果业务真需要动态路径,改用存储过程封装校验逻辑,应用层只传索引或枚举 key
JSON 字段解析和 SQL 绑定之间那层薄薄的“信任”,是最容易被忽略的攻击面。参数化不是写了 #{} 就万事大吉,而是每个从 JSON 里掏出来的值,都要重新经历“是否可信→是否白名单→是否参数化”的三重判断。

















