WallFilter是Druid中真正防SQL注入的组件,需正确配置db-type、启用校验开关(如delete-where-alway-true-check)并确保日志显示“WallFilter init with dbType: mysql”才生效,否则防护静默失效。

Druid连接池本身不防SQL注入,WallFilter 才是真正起作用的组件;只配 filters: wall 却没设 db-type 或没开校验开关,防护就等于没开。
WallFilter 为什么不是“一开就灵”
它不是基于正则的简单匹配,而是靠自研 SQL Parser 做语义分析——但这个 Parser 只解析原始 SQL 字符串,对 PreparedStatement 中的占位符(如 MyBatis 的 #{})直接跳过。所以它防的是「拼接出来的恶意 SQL」,不是「参数化之后的合法语句」。
这意味着:
-
WallFilter和PreparedStatement是互补关系,不是替代关系:前者拦住漏网的字符串拼接,后者是第一道防线 - Parser 版本必须和数据库类型对齐,比如 MySQL 场景下用
db-type: mysql,写成mysql8或mysql5就加载失败 - Spring Boot 1.2.38+ 后,
db-type不再自动推断,缺失即降级为无规则校验,日志里也不会报错,只会静默失效
怎么确认 WallFilter 真正在工作
启动时盯紧日志,必须看到类似这样的输出:
WallFilter init with dbType: mysql
没有这行,说明 WallFilter 根本没加载成功。常见原因包括:
-
druid.wall.enabled: true没配,或缩进错误(YAML 对齐敏感) -
db-type值和 JDBC URL 不一致,比如 URL 是mysql://却配了postgresql - 用了错误的 Provider,比如 Oracle 场景误配
db-type: mysql -
filters: wall,stat写成了filters: [wall, stat](部分旧 starter 不兼容数组写法)
哪些开关必须手动打开才真正拦截危险操作
默认配置下,WallFilter 对恒真条件(如 WHERE 1=1)的 DELETE 或 UPDATE 是不拦截的,必须显式启用对应开关:
-
delete-where-alway-true-check: true—— 拦截DELETE FROM t WHERE 1=1 -
update-where-alway-true-check: true—— 拦截UPDATE t SET x=1或UPDATE t SET x=1 WHERE 1=1 -
select-all-column-allow: false—— 禁用SELECT *,强制字段白名单
这些都属于 druid.wall.config 下级配置,缩进错一级就会被完全忽略,且不会报错。
绕过 WallFilter 的典型方式和应对思路
攻击者如果知道你用了 Druid,可能故意构造 Parser 难以识别的变体,比如:
- 用注释拆分关键字:
DE/**/LETE FROM user - 大小写混用:
DeLeTe(MySqlWallProvider 默认不区分大小写,但某些老版本有例外) - Unicode 编码绕过(极少见,需确认 Parser 版本是否支持全量 Unicode 归一化)
更现实的风险来自开发侧:
- 动态表名/字段名拼接(
String sql = "SELECT * FROM " + tableName),Parser 会完整解析,但这类逻辑本就不该存在 - MyBatis
${}直接拼接,WallFilter能看到最终 SQL,但此时已晚于参数化防护层
所以真正关键的不是「WallFilter 能不能拦住所有变体」,而是它能不能在你疏忽时兜底——前提是它真的加载了、配对了、开关打开了。

















