1. 背景
最近在项目中使用driud+dynamic+flyway自动执行数据库脚本的时候,碰到一些包含“if not exists” 字样的sql语句时,项目启动会报SQL注入错误。
2. 报错信息
SQL State : nullError Code : 0Message : sql injection violation, dbType mysql, , druid-version 1.2.5, syntax error: illegal name, pos 37, line 1, column 36, token IF : alter table `xxxxxxxx` add column if not exists `xxxxxx` varchar(10) comment 'xxxxxx'Location : db/migration/V001__flyway_test_add_column.sql (/xxxxxxx/V001__flyway_test_add_column.sql)Line : 1Statement : alter table `xxxxxxxx` add column if not exists `xxxxxx` varchar(10) comment 'xxxxxx'Caused by: java.sql.SQLException: sql injection violation, dbType mysql, , druid-version 1.2.5, syntax error: illegal name, pos 37, line 1, column 36, token IF : alter table `xxxxxxxx` add column if not exists `xxxxxx` at com.alibaba.druid.wall.WallFilter.checkInternal(WallFilter.java:849)at com.alibaba.druid.wall.WallFilter.check(WallFilter.java:821)at com.alibaba.druid.wall.WallFilter.statement_execute(WallFilter.java:454)at com.alibaba.druid.filter.FilterChainImpl.statement_execute(FilterChainImpl.java:3008)at com.alibaba.druid.filter.FilterAdapter.statement_execute(FilterAdapter.java:2484)at com.alibaba.druid.filter.FilterEventAdapter.statement_execute(FilterEventAdapter.java:188)at com.alibaba.druid.filter.FilterChainImpl.statement_execute(FilterChainImpl.java:3008)at com.alibaba.druid.proxy.jdbc.StatementProxyImpl.execute(StatementProxyImpl.java:147)at com.alibaba.druid.pool.DruidPooledStatement.execute(DruidPooledStatement.java:632)at org.flywaydb.core.internal.jdbc.JdbcTemplate.executeStatement(JdbcTemplate.java:244)at org.flywaydb.core.internal.sqlscript.ParsedSqlStatement.execute(ParsedSqlStatement.java:111)at org.flywaydb.core.internal.sqlscript.DefaultSqlScriptExecutor.executeStatement(DefaultSqlScriptExecutor.java:208)... 52 common frames omitted
该信息大致含义是脚本中的‘IF’关键字存在注入风险。导致driud的防火墙过滤器检查不通过。但奇怪的是,我把引入的多数据源框架dynamic注释掉后,相同的SQL脚本不会报错。所以我怀疑是苞米豆中修改了driud防火墙的策略
com.baomidou dynamic-datasource-spring-boot-starter 3.2.0
3. 解决方案
根据报错信息*com.alibaba.druid.wall.WallFilter.checkInternal(WallFilter.java:849)*找到抛出错误的地方,如下所示:
抛出该异常的正是847行,我们注意到844行有个throwException变量,那如果把这个变量变成false是不是就能解决问题?所以第一个解决方案正是修改变量值
方案一:修改throwException
点击throwException,发现该值默认true,实例化WallFilter时会从系统参数中获取,如下所示:
因此可以在启动参数或者其他地方put一个该key(ps: 我是在启动参数中增加配置项)
启动参数增加
-Ddruid.wall.throwException=false #对被认为是攻击的SQL不抛出异常-Ddruid.wall.logViolation=true #该参数是为了打印错误日志
再次启动程序,不再报错,flyway脚本也顺利执行完成!
方案二:修改filters默认值
方案一是已经检查出了攻击SQL,但是没有抛出异常而已。那么我们能不能直接不让防火墙过滤器执行呢?我之前尝试改过很多driud相关的配置项,如druid.filter.wall.enabled=false,但是我发现这些配置在集成了dynamic之后并不起作用。于是断点调试发现在数据源初始化的时候会去加载driud的防火墙配置,并且该配置项默认“监控”和“防火墙”。
我们注意到只有filters中包含wall才会开启防火墙。所以我们可以把“druid.filters”的值可以改为null或者其他值(只要不包含wall就行)
spring.datasource.dynamic.druid.filters: null 或者 stat
再次启动程序,不再报错,flyway脚本也顺利执行完成!
4. 总结
之所以报错是因为多数据源配置项默认开启了driud的防注入功能,导致 IF 这类的逻辑判断语法检查不通过。可以通过不抛出异常或者关闭filters解决该问题!!
来源地址:https://blog.csdn.net/weixin_45671892/article/details/129225768