数据库代理层不能直接拦截SQL注入,但具备SQL解析能力的代理(如ProxySQL)可通过正则匹配高危模式并拒绝请求;纯TCP透传型代理无法识别注入。

数据库代理层能拦截 SQL 注入吗
不能直接“拦截”注入语句本身,但可以基于规则识别高危模式并拒绝请求——前提是代理层具备 SQL 解析能力。纯 TCP 透传型代理(如某些 MySQL Proxy 配置)不解析 SQL,无法识别 UNION SELECT 或 OR 1=1;而支持 SQL 重写的代理(如 ProxySQL、MaxScale、自研 SQL 网关)才能做语义级干预。
ProxySQL 的 query rewrite 规则怎么防注入
ProxySQL 允许在 mysql_query_rules 表中定义匹配 + 替换逻辑,本质是正则匹配原始 SQL 文本,再决定放行、改写或阻断:
- 匹配
SELECT.*?UNION.*?SELECT并返回错误:用error_msg字段设为"SQL injection detected",状态码 503 - 过滤掉注释符:把
--.*$、/\*.*?\*/替换为空字符串,但注意这会破坏合法注释,慎用 - 强制参数化等价:对简单
WHERE id = XXX类型语句,可重写为WHERE id = ?并触发后端 Prepared Statement,但 ProxySQL 本身不执行预编译,仅靠规则无法真正“参数化”,只能配合后端驱动 - 限制关键字位置:比如只允许
ORDER BY出现在语句末尾,用正则ORDER\s+BY.*$匹配,否则拒绝
为什么不能依赖代理层替代代码层防护
代理层规则是静态文本匹配,绕过手段极多:
- 编码混淆:
%27%20OR%201%3D1(URL 编码)、0x276F7220313D31(十六进制)逃逸正则 - 大小写/空白符变形:
oR/**/1=1、UNI/**/ON可绕过简单关键字黑名单 - 盲注无特征:
AND (SELECT COUNT(*) FROM users) > 0不含典型关键字,但仍是注入 - 代理看不到应用层加密或混淆后的参数:如果前端 JS 对输入做了 base64 或异或,代理收到的是密文,无法识别原始意图
更关键的是,代理无法知道哪个字段本该是整数、哪个必须是邮箱——类型校验和业务逻辑绑定,只能在应用代码里做。
中间件层重写的实际价值在哪
它不是兜底方案,而是最后一道“兜不住也得拦一下”的网:
- 应急补丁:线上发现某接口因历史原因用了
${}拼接表名,来不及改代码时,可在 ProxySQL 加一条规则拦截含DROP或TRUNCATE的语句 - 统一审计:所有 SQL 经过代理,可记录完整原始语句 + 客户端 IP + 时间戳,用于事后溯源,比应用日志更可信
- 限流+关键词双控:对匹配
information_schema的查询自动限速至 1 QPS,避免枚举攻击拖垮数据库 - 兼容旧系统:遗留 PHP 项目用
mysql_query()且无法升级,代理层加规则至少能挡掉 70% 的显式注入流量
真正难防的从来不是 ' OR '1'='1,而是业务逻辑漏洞配合合法语法的组合拳——比如密码重置接口未校验会话状态,代理层对此完全无感。











