框架升级不能修复SQL注入漏洞,必须将代码中所有${}替换为#{}或参数化查询,并校验动态SQL的合法性。

SQL注入没被修复,只升级框架版本根本没用
单纯把 MyBatis 从 3.4.6 升到 3.5.10,或把 Spring JDBC 从 5.2.3 升到 6.1.0,**不会自动修复已有 SQL 注入漏洞**。框架升级只能堵住它自己代码里的已知漏洞(比如某版 SqlSessionTemplate 的 selectList 方法对 ${} 处理有缺陷),但你写的 SELECT * FROM user WHERE name = '${name}' 这种硬拼 SQL,新旧版本都会照常执行——漏洞在你自己的代码里,不在框架的 jar 包里。
真正要改的是 SQL 拼接方式:${} 必须换成 #{} 或参数化查询
${} 是字符串替换,#{} 才是预编译占位符。只要还在用 ${} 拼表名、字段名、ORDER BY 子句,就等于把用户输入直接喂给数据库解析器。
- 动态表名?用白名单校验后拼接,别用
${tableName}; - 动态排序字段?只允许
['id', 'created_time', 'status']中的值,再用ORDER BY #{sortField}(MyBatis)或String.format("ORDER BY %s", whiteListedField)(Java 层校验后拼); - 条件 where name like '%${keyword}%'?必须改成
WHERE name LIKE CONCAT('%', #{keyword}, '%'),让数据库自己做字符串拼接; - JDBC 原生写法?弃用
Statement,一律用PreparedStatement+setString()等方法。
升级框架前先 grep 出所有 ${} 和 Statement.execute*
不扫一遍代码,你根本不知道哪几个 ${} 是真动态、哪几个是历史遗留“假动态”(比如写死的 ${@table_prefix}user)。升级后反而可能因新版本更严格报错,暴露更多问题。
- 运行
grep -r '\$\{.*\}' src/main/java/ --include="*.xml" --include="*.java"找出全部风险点; - 检查
Statement.execute*、executeUpdate、executeQuery调用,确认是否传入了拼接字符串; - 特别注意日志埋点、导出 SQL、调试工具类——这些地方最容易偷偷用字符串拼接生成 SQL;
- MyBatis 的
<script>标签块里如果混用${}和#{},也得逐行看。
框架升级本身有兼容性雷区:Mapper 接口和 XML 易失效
MyBatis 3.5+ 对 @SelectProvider 返回值类型推断更严,Spring Boot 3.x 要求 MyBatis 3.5.13+ 且默认禁用 auto-mapping-unknown-column-behavior,老项目一升就查不到字段。
- XML 中
<resultMap>如果用了autoMapping="true",升级后可能映射失败,建议显式写全<result column="xxx" property="xxx"/>; - 自定义
TypeHandler如果继承了过时的抽象类(如BaseTypeHandler),需重写setNonNullParameter和getNullableResult两个重载方法; - Spring Boot 2.7 升 3.0 后,
mybatis-spring-boot-starter的配置项前缀从mybatis.变成mybatis.configuration.,漏改会导致配置不生效; - 升级后跑单元测试,重点看
MapperTest是否抛BindingException或空结果——大概率是 XML 路径没扫进 classpath 或命名空间写错。
最麻烦的不是升级动作本身,而是你得确认每一处 ${} 是不是真需要动态、有没有被前端绕过校验、有没有被中间件(比如网关)悄悄注入额外参数。这些没法靠版本号解决。

















