JSON扩展字段SQL注入防御方法解析与参数绑定实践
JSON字段解析后直接拼接SQL字符串存在严重注入风险。必须将所有JSON解析结果视为不可信输入,并严格使用参数化绑定(如MyBatis的` {}`)。动态字段名需通过白名单硬校验,JSON路径表达式同样需参数化或白名单控制。参数化需贯穿每个从JSON提取的值,杜绝信任假设。
# JSON字段解析后直接拼进SQL字符串,等于开门揖盗
只要把解析出来的JSON值(比如 `user.get("name")`)用 `+` 或 `String.format()` 塞进SQL字符串里,就立刻回到高危状态。哪怕前面用了 `ObjectMapper.readValue()`、做了非空校验、甚至trim了空格,都拦不住 `' OR '1'='1` 这类输入。数据库只认语法,不认“你本意是不是想查数据”。
**常见错误现象**:
- `MySQLSyntaxErrorException` 频发但SQL日志里看不出明显语法错
- 某次传 `{"status":"active' -- "}` 后查询返回全部记录
- 后台日志出现 `UNION SELECT` 或 `EXTRACTVALUE` 等报错注入特征
**必须遵守的铁律**:
1. 所有JSON解析结果(`JsonNode.asText()`、`Map.get()`、`object.field`)都必须视为不可信输入
2. 禁止对JSON字段做任何“看起来安全”的假设——比如认为status只能是active/inactive,就跳过参数化
3. 如果JSON结构固定,优先用Jackson的 `@JsonProperty` + POJO绑定,而非泛型 `Map`
## MyBatis中JSON字段必须用 `#{}`,禁用 `${}`
`${}` 是字符串替换,JSON字段值进去就是裸奔;`#{}` 才走PreparedStatement预编译。哪怕字段名来自JSON,只要它是值(不是表名、排序字段),就必须走 `#{}`。
**使用场景**:用户提交 `{"filter":{"name":"admin","age":25}}`,后端解析后用于WHERE条件。
**正确写法**:
```sql
WHERE name = #{filter.name} AND age = #{filter.age}
```
**错误写法**:
```sql
WHERE name = '${filter.name}' # 单引号包着也无效
```
**关键细节**:
- 模糊查询要加 `concat('%', #{keyword}, '%')`,不能写成 `"%${keyword}%"`
- 如果JSON里嵌套了数组(如 `{"ids":[1,2,3]}`),需转成 `IN (?, ?, ?)` 形式,用MyBatis的 `` 动态生成占位符
## 动态字段名(如JSON中的 `sortField`)必须白名单硬校验
JSON里如果带 `{"sort":"email DESC"}` 这种字段,`ORDER BY ?` 会直接报错——预编译不支持结构参数。这时候不能妥协用 `String.format("ORDER BY %s", sort)`,得靠白名单+正则双保险。
性能影响几乎为零,但漏掉一个字符就可能被绕过。
**白名单校验四步法**:
1. **定义明确白名单**:`Set.of("id", "name", "email", "created_at")`
2. **方向单独校验**:`if (!"ASC".equals(dir) && !"DESC".equals(dir)) throw new IllegalArgumentException();`
3. **完整匹配组合**:`"email DESC"` 必须整体在白名单中,不能只校验 `email` 部分
4. **拒绝特殊字符**:用 `sort.trim().replaceAll("\s+", " ")` 规范化后再比对,拒绝任何空白符、Unicode分隔符、不可见字符
## JSON路径表达式也要参数化
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里掏出来的值,都要重新经历“是否可信→是否白名单→是否参数化”的三重判断。
来源:https://www.php.cn/faq/2414983.html
本站内容用于信息整理与展示,如有侵权或内容问题请及时联系处理。
相关推荐
补充同频道和同主题内容,方便继续浏览更多相关内容。
同类最新
继续查看同栏目最近更新的文章。
MyBatis Hive多表关联实现方法
MyBatis处理Hive多表关联查询与普通数据库类似。需准备映射文件,使用association和collection标签定义关联;创建Java实体类包含集合成员变量承接一对多关系;编写Mapper接口声明查询方法;配置MyBatis环境注册映射;最后通过SqlSession调用即可获取关联数据。
提升Hive Metastore查询速度的有效方法
HiveMetastore查询优化需从存储优化、缓存机制、查询策略、索引构建、并行能力、配置调优、硬件升级、数据分区及定期维护等多方面协同入手,综合提升系统吞吐量与响应速度,有效降低查询延迟。
Hive Metastore处理大数据的核心机制
HiveMetastore管理元数据,通过分库分表、读写分离应对海量元数据,调整JVM堆内存并采用G1GC提升稳定性,利用HDFS或云存储及CBO优化器加速查询,在大数据场景下提供高效元数据服务。
Kafka Coordinator 如何监控集群的完整方法与最佳实践指南
Kafka协调器监控可通过命令行工具、KafkaManager及JMX实时查看消费者滞后、分区状态等性能指标,并利用Prometheus+Grafana实现长期可视化监控与告警,从而确保集群稳定运行。
Hive中row_number()函数性能的实用高效监控方法与优化技巧
Hive中row_number()性能受数据量、索引、查询复杂度及数据倾斜影响。优化需通过分区、建索引、查询优化、使用ORC Parquet格式及调整CBO和并行度实现。监控可借助HiveWebUI、YARN界面、日志或第三方工具定位瓶颈,持续迭代改进。
