【分享】Druid升级后出现的永真拦截问题

今天闲来无事升级了下项目中的jar包,把Druid从1.2.20升级到了1.2.23,想着只是一个小版本号的升级,应该不会有啥问题,本地盲测了一下,没想到竟然出幺蛾子了。

com.jfinal.plugin.activerecord.ActiveRecordException: java.sql.SQLException: sql injection violation, dbType mysql, druid-version 1.2.23, select alway true condition not allow : select count(*) from
		sys_user_login a
	left join 
		sys_user b on b.id = a.user_id
	where
		1=1
		
		at com.alibaba.druid.wall.WallFilter.checkInternal(WallFilter.java:883) ~[druid-1.2.23.jar:?]
	at com.alibaba.druid.wall.WallFilter.connection_prepareStatement(WallFilter.java:318) ~[druid-1.2.23.jar:?]
	at com.alibaba.druid.filter.FilterChainImpl.connection_prepareStatement(FilterChainImpl.java:547) ~[druid-1.2.23.jar:?]
	at com.alibaba.druid.proxy.jdbc.ConnectionProxyImpl.prepareStatement(ConnectionProxyImpl.java:328) ~[druid-1.2.23.jar:?]
	at com.alibaba.druid.pool.DruidPooledConnection.prepareStatement(DruidPooledConnection.java:369) ~[druid-1.2.23.jar:?]
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[?:1.8.0_172]
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[?:1.8.0_172]
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[?:1.8.0_172]
	at java.lang.reflect.Method.invoke(Method.java:498) ~[?:1.8.0_172]

核心的错误其实就这一句了:select alway true condition not allow。意思就是说where后面不允许出现永真的条件,比如1=1。

1=1的写法多用于多条件动态查询,是为了解决拼接and时不致于出现语法问题。但是从报错看,是不允许这么玩了。于是查了下资料。

网上有三种解决方案吧:一、避免使用1=1,但是我现在来不及改。二、取消wall防火墙,但是我认为取消后会影响安全性。三、wallConfig.setConditionAndAlwayTrueAllow(true);试了不管用,而且我发现人家默认就是true。

没办法,以上方法均不可行,于是自己查Druid的源码,发现了以下问题。

问题一Druid的永真检测一直以来都是默认开启的,但是之前的版本中为什么没有生效?这竟然是长期以来的一个bug!

image.png

传送门:https://github.com/qxo/druid/commits/refs/heads/fix-wall-deleteWhereAlwaysTrue/

我一开始比对两个版本的源代码时发现,核心的判断逻辑确实不一样,还以为改了设计,原来是之前的逻辑写错了。_(¦3」∠)_

1.2.20_ys.png

1.2.23_ys.png

PixPin_2024-10-17_19-41-35~2.png

问题二从上面的源代码中可以看出,永真检测确实可以关闭,但不是针对conditionAndAlwayTrueAllow这个参数,而是selectWhereAlwayTrueCheck这个参数。

wall防火墙的其他配置,我发现了一篇文章,写的很全,分享一下:https://www.cnblogs.com/chenglc/p/9983799.html

解决方案

所以,在jfinal中如何关闭druid的永真检测?下面上方案。

public void configPlugin(Plugins me) {
    DruidPlugin druidPlugin = getDruidPlugin();
    wallFilter = new WallFilter();
    wallFilter.setDbType("mysql");
    // 关闭永真检测
    WallConfig wallConfig = new WallConfig();
    wallConfig.setSelectWhereAlwayTrueCheck(false);
    wallFilter.setConfig(wallConfig);
    //增加过滤器
    druidPlugin.addFilter(wallFilter);
    druidPlugin.addFilter(new StatFilter());
    me.add(druidPlugin);

    ......
}

写在最后

说到底,都是为了解决多参数动态查询问题,我现在的sql都是写在外部文件中的,通过isNotEmpty来动态拼接查询语句。大家是如何解决这个动态查询问题的,有没有更优雅的解决方案?

评论区

JFinal

2024-10-17 23:06

where 1=1 大量被使用,这个分享很有价值,点赞加收藏,以后用得上

热门分享

扫码入社