当前位置: 首页
数据库
如何解决Spring Data JPA中的SQL注入问题_利用Query注解的命名参数

如何解决Spring Data JPA中的SQL注入问题_利用Query注解的命名参数

热心网友 时间:2026-04-30
转载

如何解决Spring Data JPA中的SQL注入问题:利用Query注解的命名参数 Query注解里用字符串拼接就是SQL注入温床 在 @Query 注解的 JPQL 或原生 SQL 字符串里,直接用 + 号拼接用户输入,这无异于把数据库的钥匙直接交给了请求参数。虽然 JPQL 不支持将预编译占

如何解决Spring Data JPA中的SQL注入问题:利用Query注解的命名参数

如何解决Spring Data JPA中的SQL注入问题_利用Query注解的命名参数

Query注解里用字符串拼接就是SQL注入温床

@Query 注解的 JPQL 或原生 SQL 字符串里,直接用 + 号拼接用户输入,这无异于把数据库的钥匙直接交给了请求参数。虽然 JPQL 不支持将预编译占位符(比如 ?1)与动态字段名或表名混合使用,但命名参数(:name)本身是安全的——前提是,别用它去拼接 SQL 语句的结构部分。

命名参数只能绑定值,不能绑定列名或表名

这里有个最常见的误区:以为写了 @Query("SELECT * FROM :table WHERE name = :name") 就算用了命名参数。实际上,:table 会被当作一个普通的字面量字符串处理,而不是进行参数替换,运行时要么直接报错,要么查不到任何数据。JPA 规范明确禁止在运行时解析动态的表名或列名。

  • :param 只能出现在 WHERE、HA VING、ORDER BY(值部分)、GROUP BY(值部分)这类**值上下文**中。
  • 表名、列名、函数名、排序方向(ASC/DESC)这些结构部分,必须硬编码在 SQL 里,或者经过外部严格校验后,通过白名单机制进行拼接。
  • 如果业务上确实需要动态表名,建议改用 JdbcTemplate 配合白名单校验和 PreparedStatement,别强行塞进 @Query 里。

安全写法:命名参数 + 严格类型约束 + 白名单兜底

下面这个例子看起来平平无奇,但每一步其实都在为安全加锁:

@Query("SELECT u FROM User u WHERE u.status = :status AND u.name LIKE %:name%")
List findUsers(@Param("status") Integer status, @Param("name") String name);
  • status 参数是 Integer 类型,JPA 底层会自动将其转换为 JDBC 的 setInt() 调用,从根本上杜绝了字符串逃逸的可能。
  • name 参数虽然是 String 类型,但它只用于 LIKE 右侧的模糊匹配,而且通配符 % 是直接写死在 SQL 语句里的,并非从参数中拼接进来。
  • 如果业务要求按多个状态进行筛选,千万别写成 "status IN :statuses"(JPA 不支持直接将数组参数展开到 IN 子句中)。正确的做法是,动态构建 IN 子句,并配合一个经过白名单校验的枚举值列表。

原生 SQL 下命名参数仍安全,但得避开 CONCAT 和字符串函数

当使用 @Query(nativeQuery = true) 切换到原生 SQL 时,命名参数依然会走 JDBC 的预编译机制,安全性有保障。但需要注意的是,某些数据库函数可能会绕过参数化机制,带来隐患:

  • 避免使用 CONCAT(:a, :b):col = :val 这类将参数当作标识符来用的写法。
  • 像 PostgreSQL 的 quote_ident(:table) 函数,看起来能安全处理标识符,但 JPA 本身并不识别这个函数,传进去的仍然是一个未经转义的字符串。
  • 真正需要动态字段时,稳妥的做法是:先用工具类(如 StringUtils.replaceChars(fieldName, ".", "_"))进行基础清洗,再与预设的白名单(例如 Set.of("user_name", "created_at"))进行比对。如果不匹配,直接抛出 IllegalArgumentException 异常。

话说回来,最棘手的问题往往不在于参数怎么写,而在于团队中可能有人在 Service 层偷偷用 String.format 拼接好 SQL,再丢给 JdbcTemplate 去执行。这种代码在编译时不会报错,但只要参数里包含一个单引号或分号,就等于为攻击者敞开了大门。所以,盯紧日志里打印出的最终 SQL 语句,比任何编码规范都更管用。

来源:https://www.php.cn/faq/2328747.html

游乐网为非赢利性网站,所展示的游戏/软件/文章内容均来自于互联网或第三方用户上传分享,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系youleyoucom@outlook.com。

同类文章
更多
得物OceanBase数据库落地实践技术解析与经验总结

得物OceanBase数据库落地实践技术解析与经验总结

得物引入OceanBase多模数据库,解决了多品类数据库运维复杂、成本高的问题。通过分层转储、增量合并和两层压缩技术,存储成本降低40%以上;多活架构保障高可用;复杂SQL性能提升130-200倍。迁移后SQL平均耗时下降88 3%,成本降低43%,存储压缩率达80%以上,实现TP AP一体化架构。

时间:2026-07-19 07:26
GraphQL深度解析:为什么它能替代传统REST API的核心原因

GraphQL深度解析:为什么它能替代传统REST API的核心原因

GraphQL是一种新型API查询语言,通过按需查询精准获取数据,有效解决了REST过度获取与获取不足的问题,采用单一端点和强类型Schema降低维护成本,原生支持查询、变更与订阅,统一数据交互协议,正逐步替代传统RESTAPI。

时间:2026-07-19 07:26
Redis哨兵搭建与ACL权限控制全流程实现详解教程

Redis哨兵搭建与ACL权限控制全流程实现详解教程

基于一主二从三哨兵架构部署Redis集群,编译并配置主节点、从节点及哨兵节点。通过ACL机制实现用户权限精细控制,为default、app-user、sentinel-user、replica-user用户分配密码与权限。启动各节点后,验证主从同步及哨兵状态正常。

时间:2026-07-19 07:26
MySQL Binlog CDC全链路实现方法详解

MySQL Binlog CDC全链路实现方法详解

MySQL数据库通过Binlog实现CDC全链路,覆盖从业务代码变更到应用消费端的完整流程。Binlog生成依赖两阶段提交,保证仅捕获已提交的事务数据;必须采用ROW格式记录每行变更前后的值,从而实现精准的数据同步与消费,确保数据一致性。

时间:2026-07-19 07:26
Oracle与MySQL数据库批量插入更新方法

Oracle与MySQL数据库批量插入更新方法

Oracle通过mergeinto实现存在更新、不存在插入,但更新时不能修改关联条件字段;MySQL通过insertinto onduplicatekeyupdate,依赖唯一索引触发更新,无此限制。两者语法差异显著,需注意约束差异,根据数据库特性选择合适写法,避免数据不一致,并考虑不同场景。

时间:2026-07-19 06:54
热门专题
更多
刀塔传奇破解版无限钻石下载大全 刀塔传奇破解版无限钻石下载大全
洛克王国正式正版手游下载安装大全 洛克王国正式正版手游下载安装大全
思美人手游下载专区 思美人手游下载专区
好玩的阿拉德之怒游戏下载合集 好玩的阿拉德之怒游戏下载合集
不思议迷宫手游下载合集 不思议迷宫手游下载合集
百宝袋汉化组游戏最新合集 百宝袋汉化组游戏最新合集
jsk游戏合集30款游戏大全 jsk游戏合集30款游戏大全
宾果消消消原版下载大全 宾果消消消原版下载大全
  • 热门数据榜