mybatis-plus SQL 注入漏洞导致版本升级引发的问题

前言

最近做项目,对于企业级而言 JDK 和 Spring 的升级不能一蹴而就,而且 OpenJDK11 的支持时间不多了,升级到 JDK17 风险太大,所以缝缝补补,但是mybatis-plus 需要升级,这个就没办法了,其实这次漏洞影响的是 QueryWrapper 或者 UpdateWrapper 在动态 SQL 时通过调用方法com.baomidou.mybatisplus.core.toolkit.sql.SqlInjectionUtils检查是否特殊 SQL 字符防注入。本身是日常升级,但是升级出事了。

准备 demo

POM

XML 复制代码
<dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
            <version>2.7.18</version>
        </dependency>
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-api</artifactId>
            <version>1.7.36</version>
        </dependency>
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>2.3.2</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-jdbc</artifactId>
            <version>2.7.18</version>
        </dependency>
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <version>3.5.7</version>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.33</version>
        </dependency>
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>3.5.7</version>
        </dependency>
    </dependencies>

随便写个 demo

java 复制代码
@Mapper
public interface DemoDao {

    @Select("select * from user where name = #{name}")
    List<User> selectUser(String name);
}

@RestController
public class DemoController {

        @Autowired
        private DemoDao demoDao;

        @RequestMapping("/user")
        public List<User> listUser(String name){
            return demoDao.selectUser(name);
        }
}

@SpringBootApplication
@MapperScan(basePackages = "com.boot.mybatis.plus.demo.dao")
public class MybatisPlusMain {
    public static void main(String[] args) {
        SpringApplication.run(MybatisPlusMain.class, args);
    }
}

配置一个数据源即可

jar 冲突 1

启动上面是示例,发现失败了,原因是 mybatis-plus 的 3.5.7 和 mybatis 的 3.5.7 冲突,mybatis 3.5.7 较旧

bash 复制代码
2025-11-03 21:12:38.910 ERROR 1625 --- [           main] o.s.b.d.LoggingFailureAnalysisReporter   : 

***************************
APPLICATION FAILED TO START
***************************

Description:

An attempt was made to call a method that does not exist. The attempt was made from the following location:

    com.baomidou.mybatisplus.core.MybatisMapperAnnotationBuilder$AnnotationWrapper.<init>(MybatisMapperAnnotationBuilder.java:653)

The following method did not exist:

    org.apache.ibatis.annotations.Select.affectData()Z

The calling method's class, com.baomidou.mybatisplus.core.MybatisMapperAnnotationBuilder$AnnotationWrapper, was loaded from the following location:

    jar:file:/Users/huahua/.m2/repository/com/baomidou/mybatis-plus-core/3.5.7/mybatis-plus-core-3.5.7.jar!/com/baomidou/mybatisplus/core/MybatisMapperAnnotationBuilder$AnnotationWrapper.class

The called method's class, org.apache.ibatis.annotations.Select, is available from the following locations:

    jar:file:/Users/huahua/.m2/repository/org/mybatis/mybatis/3.5.7/mybatis-3.5.7.jar!/org/apache/ibatis/annotations/Select.class

The called method's class hierarchy was loaded from the following locations:

    org.apache.ibatis.annotations.Select: file:/Users/huahua/.m2/repository/org/mybatis/mybatis/3.5.7/mybatis-3.5.7.jar


Action:

Correct the classpath of your application so that it contains compatible versions of the classes com.baomidou.mybatisplus.core.MybatisMapperAnnotationBuilder$AnnotationWrapper and org.apache.ibatis.annotations.Select

查看源码发现

根据 maven 仓库分析

mybatis-plus 3.5.7 依赖 mybatis3.5.16

jar 冲突 2

升级 mybatis 版本到 3.5.16 后,如果同时使用 spring-data-jpa,那么 jsqlparser 就会冲突

本身而言只有 mybatis-plus 强依赖这个 jar,但是实际上 spring-data-jpa(除了 CN 基本上都是使用 jpa) 也隐形的依赖了这个 jar,且版本号与 mybatis-plus 不一样

但是是 optional,但是又是 provided 修饰

在org.springframework.data.jpa.repository.query.QueryEnhancerFactory中就会判断

发现有些类不存在,如果引入了 spring-data-jpa,不使用 jpa还好,如果使用则会 启动报错

解决办法有 2 个:

  • mybatis-plus 排除 jsqlparser
  • 使用低版本的 jsqlparser,比如 3.1,既不能使用 mybatis-plus 依赖的高版本,也不能使用 spring-data-jpa 的 4.5 版本,不兼容

QueryWrapper IN 查询

java 复制代码
@Mapper
public interface DemoDao {

    @Select("select * from User ${ew.customSqlSegment}")
    List<User> selectUser(@Param(Constants.WRAPPER) QueryWrapper<User> queryWrapper);
}

        @RequestMapping("/user")
        public List<User> listUser(String name){
            QueryWrapper<User> queryWrapper = new QueryWrapper<>();
            queryWrapper.in("name", Collections.emptySet());
            return demoDao.selectUser(queryWrapper);
        }

适当改造代码,执行 http 访问

bash 复制代码
### Error querying database.  Cause: java.sql.SQLSyntaxErrorException: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '))' at line 1
### The error may exist in com/boot/mybatis/plus/demo/dao/DemoDao.java (best guess)
### The error may involve com.boot.mybatis.plus.demo.dao.DemoDao.selectUser-Inline
### The error occurred while setting parameters
### SQL: select * from User WHERE (name IN ())
### Cause: java.sql.SQLSyntaxErrorException: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '))' at line 1
; bad SQL grammar []; nested exception is java.sql.SQLSyntaxErrorException: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '))' at line 1] with root cause

java.sql.SQLSyntaxErrorException: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '))' at line 1

SQL:select * from User WHERE (name IN ())

这个在 mybatis-plus 3.4 以下的版本可以正常运行,先看看 mybatis-plus 3.4 与之后的逻辑

其实 mybatis-plus 已经明确说明了,看看代码

看看 SQL 是怎么拼接的,因为是动态 SQL,所以每次动态拼接

org.apache.ibatis.parsing.GenericTokenParser

同理这里可以配置过滤器检查 SQL

看看 mybatis-plus 3.3.2 呢

其实为 null 会空指针,只有空集合元素才会不拼接

所以 mybatis-plus 3.4 以下不会出现问题,当然可能空指针

总结

mybatis-plus 真是一言难尽啊,国外基本上是使用 jpa,其实 mybatis 也有 jpa,mybatis-plus 和 spring-data-jpa 存在 jsqlparser 隐形冲突,mybatis-plus 和 mybatis 对相同 id 的处理不一样:https://blog.csdn.net/fenglllle/article/details/134912102。升级后 QueryWrapper IN处理空集合的逻辑不一样,这种需要全覆盖测试才行,否则特殊数据就......建议为了减少问题,只使用一样,比如 mybatis-plus 与 spring-data-jpa 二选一,另外尽量不使用 query wrapper 这样的动态 SQL 拼接,建议使用代码动态拼接。

相关推荐
呆呆小金人2 小时前
SQL字段对齐:性能优化与数据准确的关键
大数据·数据仓库·sql·数据库开发·etl·etl工程师
learning-striving2 小时前
SQL server创建数据表
数据库·sql·mysql·sql server
Yeats_Liao2 小时前
时序数据库系列(三):InfluxDB数据写入Line Protocol详解
数据库·后端·时序数据库
天地之于壹炁兮2 小时前
编程I/O入门指南:核心操作全解析
数据库·windows·microsoft
切糕师学AI2 小时前
SQL中的函数索引/表达式索引
数据库·sql·mysql·postgresql·oracle
武子康2 小时前
Java-166 Neo4j 安装与最小闭环 | 10 分钟跑通 + 远程访问 Docker neo4j.conf
java·数据库·sql·docker·系统架构·nosql·neo4j
S_h_a_3 小时前
八股-Mysql 基础篇(1)
数据库·mysql
Dxy12393102163 小时前
MySQL的GROUP_CONCAT函数详解
数据库·mysql
编啊编程啊程3 小时前
【029】智能停车计费系统
java·数据库·spring boot·spring·spring cloud·kafka