在批量插入数据时如何在JDBC中防止动态SQL注入

冬伟大大_7937

冬伟大大_7937

2026-10-15

618人浏览

原创

preparedstatement仅防参数位置注入,不防sql结构注入;表名、列名、order by等非参数位置必须白名单校验,否则拼接即失效。

在批量插入数据时如何在jdbc中防止动态sql注入

为什么 PreparedStatement 不能自动防住所有注入场景

很多人以为只要用了 PreparedStatement,就彻底安全了。其实不然——它只防“参数位置上的注入”,不防“SQL结构层面的注入”。比如你拼接表名、字段名、ORDER BY 子句或 WHERE 条件逻辑时用了字符串拼接,哪怕参数全用 ? 占位,照样可能被绕过。

典型翻车现场:"INSERT INTO " + tableName + " (id, name) VALUES (?, ?)",如果 tableName 来自配置或上游数据(比如从消息头里取的库名),攻击者控制该值就能写成 users; DROP TABLE orders;,数据库会执行两条语句(取决于驱动和数据库是否允许多语句)。

  • MySQL 默认禁用多语句,但加了 allowMultiQueries=true 就危险了
  • PostgreSQL 不支持多语句,但可借 UNION SELECT 泄露元数据
  • 表名/列名无法用 ? 占位,必须靠白名单校验或转义

动态表名和字段名必须走白名单校验

凡是出现在 SQL 模板中非参数位置的字符串(如 INSERT INTO ? 是非法的,INSERT INTO users 才合法),都得提前约束范围。不要试图用正则过滤单引号或分号——字符集编码、Unicode 变体、注释绕过手段太多,白名单才是唯一靠谱方式。

实操建议:

知了追踪
知了追踪

一款AI开发辅助工具,主要用于AI智能信息助手,智能追踪你的兴趣资讯,适合需要提升相关任务效率的用户。

下载
  • 把允许的表名硬编码进枚举或配置 Map,比如 Map.of("order_log", "t_order_log_2026", "user_profile", "t_user_profile")
  • 运行时只接受 key,查表映射出真实表名,拒绝任何不在 key 列表中的输入
  • 字段名同理:插入前校验 fieldList 是否全在预定义集合内,比如 Set.of("user_id", "amount", "status")
  • 避免用反射或 JSON key 动态生成字段列表,除非你能保证这些 key 绝对不可控

批量插入时别混用 Statement 和 PreparedStatement

有人为了“灵活”在批处理里切回 Statement,比如先用 PreparedStatement 插基础字段,再用 Statement 补一条 UPDATE 或 INSERT ... SELECT。这等于主动拆掉防护墙——Statement 对任何字符串都不做转义,传入含 /* 注释或 1=1 的值就直接执行。

正确做法是统一用 PreparedStatement,哪怕要拼复杂子查询:

  • 把子查询逻辑移到应用层,查出来再塞进主 INSERT 的参数里
  • 用数据库函数替代动态条件,比如 COALESCE(?, 'default') 而不是拼 "WHERE status = '" + status + "'"
  • 真需要动态 WHERE,改用 MyBatis 的 <if></if> 标签或 jOOQ 的 DSL,它们底层仍走预编译

rewriteBatchedStatements=true 不影响注入防护,但会放大错误后果

MySQL 驱动加了 rewriteBatchedStatements=true 后,JDBC 会把 1000 条 INSERT INTO t VALUES (?) 改写成一条 INSERT INTO t VALUES (?), (?), ...。这个优化本身不破坏 PreparedStatement 的安全性,因为所有值仍是参数化传入。

但它会让一次注入的影响面变大:原本只污染单条记录的恶意值,现在可能让整批 1000 条都失败,甚至因语法错误导致整批回滚。更麻烦的是,错误日志里只报“第 1 行语法错误”,你根本不知道是哪条数据带了坏字符。

  • 上线前务必用含单引号、反斜杠、Unicode 零宽空格的数据压测批处理逻辑
  • 在 addBatch() 前加一层清洗,比如 value.replaceAll("\u200b", "") 干掉零宽字符
  • 批大小别设太大(建议 ≤500),否则定位脏数据成本陡增
真正难防的不是用户输错一个单引号,而是你把“可控性”误判为“可信性”。表名看着来自配置文件,但配置文件本身可能被上游服务篡改;字段名看似固定,但前端传来的 JSON key 名却悄悄映射到了 INSERT 的列列表里。这些地方没白名单、没校验、没日志留痕,PreparedStatement 再好也救不了。

相关文章

PHP速学视频免费教程(入门到精通)
PHP速学视频免费教程(入门到精通)

PHP怎么学习?PHP怎么入门?PHP在哪学?PHP怎么学才快?不用担心,这里为大家提供了PHP速学教程(入门到精通),有需要的小伙伴保存下载就能学习啦!

下载

相关标签:

sql注入

本站声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

相关专题

更多
数据分析工具有哪些
数据分析工具有哪些

数据分析工具有Excel、SQL、Python、R、Tableau、Power BI、SAS、SPSS和MATLAB等。详细介绍:1、Excel,具有强大的计算和数据处理功能;2、SQL,可以进行数据查询、过滤、排序、聚合等操作;3、Python,拥有丰富的数据分析库;4、R,拥有丰富的统计分析库和图形库;5、Tableau,提供了直观易用的用户界面等等。

2023.10.12

4243

8

SQL中distinct的用法
SQL中distinct的用法

SQL中distinct的语法是“SELECT DISTINCT column1, column2,...,FROM table_name;”。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

2023.10.27

891

4

SQL中months_between使用方法
SQL中months_between使用方法

在SQL中,MONTHS_BETWEEN 是一个常见的函数,用于计算两个日期之间的月份差。想了解更多SQL的相关内容,可以阅读本专题下面的文章。

2024.02.23

1109

5

SQL出现5120错误解决方法
SQL出现5120错误解决方法

SQL Server错误5120是由于没有足够的权限来访问或操作指定的数据库或文件引起的。想了解更多sql错误的相关内容,可以阅读本专题下面的文章。

2024.03.06

6161

10

sql procedure语法错误解决方法
sql procedure语法错误解决方法

sql procedure语法错误解决办法:1、仔细检查错误消息;2、检查语法规则;3、检查括号和引号;4、检查变量和参数;5、检查关键字和函数;6、逐步调试;7、参考文档和示例。想了解更多语法错误的相关内容,可以阅读本专题下面的文章。

2024.03.06

3003

4

oracle数据库运行sql方法
oracle数据库运行sql方法

运行sql步骤包括:打开sql plus工具并连接到数据库。在提示符下输入sql语句。按enter键运行该语句。查看结果,错误消息或退出sql plus。想了解更多oracle数据库的相关内容,可以阅读本专题下面的文章。

2024.04.07

6120

11

sql中where的含义
sql中where的含义

sql中where子句用于从表中过滤数据,它基于指定条件选择特定的行。想了解更多where的相关内容,可以阅读本专题下面的文章。

2024.04.29

8261

6

sql中删除表的语句是什么
sql中删除表的语句是什么

sql中用于删除表的语句是drop table。语法为drop table table_name;该语句将永久删除指定表的表和数据。想了解更多sql的相关内容,可以阅读本专题下面的文章。

2024.04.29

1130

5

sql中删除一列的命令是什么
sql中删除一列的命令是什么

在sql中,使用alter table语句可以删除一列,语法为:alter table table_name drop column column_name。想了解更多sql的相关内容,可以阅读本专题下面的文章。

2024.04.29

992

5

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
PHP开发基础之数据库篇(PDO)
PHP开发基础之数据库篇(PDO)

共10课时 | 2.3万人学习