批量查询接口易出SQL注入,因开发者常字符串拼接IN列表(如"id IN (" + ids + ")”),未逐个校验或参数绑定;恶意输入如"1,2,3' OR '1'='1"可破坏语义,执行任意逻辑。

批量查询接口为什么容易出SQL注入
因为批量操作常要一次查多个ID,比如 id IN (1,2,3),开发者习惯用字符串拼接构造括号里的列表,而没对每个ID做类型校验或参数绑定。一旦传入 1,2,3' OR '1'='1 这类恶意值,整个 IN 子句就被破坏,变成可执行任意逻辑的入口。
别用字符串拼接构建 IN 列表
这是最常见也最危险的做法。例如 Java 中写 String ids = "1,2,3"; query = "SELECT * FROM user WHERE id IN (" + ids + ")";,哪怕 ids 来自后端校验,只要中间环节有缓存、日志重放或前端绕过,就可能失控。
- 必须把每个 ID 单独作为参数绑定,不能“一次性拼成字符串再塞进去”
- MySQL/PostgreSQL 支持动态占位符数量,但 JDBC 驱动不原生支持;得用
PreparedStatement配合循环设参,或改用 MyBatis 的<foreach>标签(底层仍走预编译) - 如果硬要用拼接(如某些老框架不支持动态参数),至少先用
Integer.parseInt()强转每个 ID,捕获NumberFormatException并拒绝非法输入
MyBatis 批量查询怎么防注入
很多人以为用了 MyBatis 就安全了,其实错在误用 ${} —— 它是字符串替换,不是参数绑定。只要看到 WHERE id IN (${ids}),就等于开了后门。
- 必须用
#{},配合<foreach>:<select id="batchSelect" resultType="User"> SELECT * FROM user WHERE id IN <foreach item="id" collection="idList" open="(" separator="," close=")"> #{id} </foreach> </select> - collection 参数名必须和传入 Map 或对象字段名一致,否则
idList为空导致 SQL 语法错误 - Oracle 对 IN 列表长度有限制(通常 1000 项),超限时得拆成多批次,不能靠拼长字符串绕过
JSON 数组传参时的陷阱
前端常传 {"ids": [1,2,"3' OR 1=1--"]},后端若直接取 request.getParameter("ids") 再 JSON 解析,再拼进 SQL,就又回到原始漏洞路径。
- 解析后立刻对每个元素做类型强校验:整数必须是
Long或Integer,不能是字符串 - Spring Boot 推荐用
@RequestBody List<Long> ids,框架会自动拒绝非数字项并返回 400,比手动解析更可靠 - 不要在 DAO 层再做字符串拼接——哪怕你“确认”数据干净,也要假设上游已失守
真正卡住批量注入的点,不在“怎么拼 SQL”,而在“谁负责校验每一个值”。一个 IN 列表里混进一个非法字符串,整条语句就失效。没人会逐个检查日志里每一条查询,但攻击者只需要一次成功。

















