数据库安全网关是应用层防御失效时的最后一道拦截,必须支持语义级AST解析、部署于数据库统一入口、分等级实施策略。

单靠代码层的 PreparedStatement 或 #{} 不能拦住所有 SQL 注入,这是现实里踩过坑的人才懂的事。
为什么应用层防御一定会漏掉一部分注入流量
不是开发不认真,而是有些路径根本绕不开参数绑定:
- MyBatis 的
${}语法在动态表名、排序字段等场景下无法避免,一旦输入没做白名单校验,ORDER BY ${sortField}就是裸奔入口 - 遗留系统里大量
String.format("SELECT * FROM %s", tableName),改起来要动几十个模块,上线排期卡在运维审批上 - ETL 工具、DBA 命令行直连、报表系统绕过连接池走从库——这些流量压根不经过你的 Java/PHP 应用代码
- 第三方 SDK(比如某些老版本的 Elasticsearch JDBC bridge)内部拼 SQL,你连源码都改不了
这时候如果只依赖应用层,等于把数据库大门钥匙挂在门口,还指望没人捡。
数据库安全网关必须支持 AST 解析,否则就是假防护
正则匹配 UNION SELECT 或过滤 -- 这类规则,早被攻击者玩烂了:
-
SEL/**/ECT、unIoN/**/sElEcT能轻松绕过大小写+注释混淆 - Base64 编码后的
' OR 1=1 --在请求体里根本不会触发关键词告警 - MySQL 8.0 的 CTE 递归查询、PostgreSQL 的
WITH RECURSIVE,正则根本没法识别语义结构
真正有效的网关会把整条 SQL 解析成抽象语法树(AST),然后判断 WHERE 子句中是否出现「非绑定变量的布尔表达式」。它能准确区分 WHERE id = ? 和 WHERE id = 1 OR 1=1,哪怕后者藏在五层嵌套注释里。
部署位置决定网关有没有用,不是插在主库前面就万事大吉
如果只串在应用和主库之间,但以下路径仍然存在:
- 应用服务器直连从库查报表(
jdbc:mysql://slave-db:3306) - DBA 用
mysql -h prod-slave -u admin -p登录做数据核对 - 定时任务脚本通过
psql -h pg-warehouse同步数据
那网关实际覆盖不到 40% 的 SQL 流量。必须把网关部署在数据库统一入口(比如 VIP 或 DNS 层),所有客户端连接都强制经过它,包括命令行、ETL、备份工具——否则策略再严,也是纸糊的墙。
最常被忽略的一点:AST 解析能力不是默认开启的,很多网关需要手动启用「语义分析模式」并加载对应数据库的语法插件;而部署位置变更后,原有连接池配置、SSL 证书信任链、甚至超时时间都可能出问题——这些细节不提前验证,上线当天就会丢连接。

















