shardingsphere或mycat等分库分表中间件的sql拦截不靠谱,因其仅对拆分后的片段sql做特征匹配,无法感知原始恶意输入;攻击者可通过注释、大小写混写、url编码绕过规则,且中间件不校验参数绑定逻辑,无法拦截未参数化的表名、排序字段等动态语法,更无法覆盖cli脚本、定时任务等非http路径调用。

中间件层无法替代应用层参数化,统一拦截必须作用于数据库驱动入口,否则等于没防。
为什么ShardingSphere或MyCat的SQL拦截不靠谱
分库分表中间件(如ShardingSphere-Proxy)对UNION SELECT、OR 1=1这类特征做规则匹配,但攻击者用/**/注释、大小写混写(Or 1=1)、URL编码(%6f%72%203333%3d3333)就能绕过。更关键的是,中间件看到的往往是拆分后的片段SQL——比如SELECT * FROM order_2024 WHERE user_id = ?,它合法,但原始请求可能是user_id=1 OR '1'='1,参数还没传进去就已透传。
常见错误现象:sql-show=true日志里全是问号,查不到真实输入;WAF在接入层拦住了id=1'--,但后台定时任务直连物理库,完全不走WAF。
- 中间件只校验SQL模板结构,不校验参数绑定逻辑
- 连接池复用导致
SET app.user_id = 'xxx'污染后续会话,RLS策略失效 - 分片路由时若
shard_key = ?未参数化,恶意值直接透传到物理节点
真正有效的中间件层统一防护怎么做
不是加个WAF规则,而是把防护点下沉到数据库驱动封装层——所有db.Query()、stmt.Exec()调用前强制检查原始SQL字符串是否含用户变量。
- Go场景:重写
database/sql.Conn的QueryContext方法,若query中出现${、+、fmt.Sprintf痕迹,立即panic("raw SQL with interpolation detected") - Java场景:用Byte Buddy或ASM在类加载期hook
PreparedStatement.execute(),确保sql字段不含运行时拼接痕迹 - Python场景:monkey patch
psycopg2.cursor.execute(),对sql参数做AST解析,拒绝含f"WHERE id = {x}"结构的调用
特别注意:CLI脚本、Seata事务补偿器、MQ消费逻辑这些非HTTP路径,必须复用同一套驱动层hook,否则就是漏洞盲区。
动态语法位置(表名、排序字段)怎么兜底
SELECT * FROM ?和ORDER BY ?在MySQL/PostgreSQL里直接报错:ERROR: syntax error at or near "?"。这时候白名单不是“可选优化”,是唯一出路。
- 表名校验:从配置中心读取
sharding-tables=["order_2024", "order_2025"],用in_array(table_name, valid_tables)硬校验,不匹配直接HTTP 400 - 排序字段映射:用户传
sort=created,代码里map[string]string{"created": "created_at", "score": "final_score"}转译,禁止拼接原始输入 - LIMIT数值:必须用
int类型强转并限幅(如min(max(limit, 1), 1000)),不能接受"1000; DROP TABLE users"这种字符串
别信正则过滤——/^[a-zA-Z0-9_]+$/挡不住user_id; DROP TABLE users,因为分号在列名上下文里是合法字符。
分布式事务中容易被忽略的注入点
一笔跨库转账涉及UPDATE account SET balance = balance - ? WHERE id = ?和INSERT INTO log (msg) VALUES (?),如果第二条语句的msg是拼接的"transfer from "+uid,整笔XA事务就成了后门。
- 检查每个
UPDATE/INSERT的SET和WHERE子句是否全部参数化,不能只盯主查询 - 避免在事务内调用存储过程并传入用户输入——TiDB/CockroachDB不支持带参跨节点SP,实际执行退化为客户端拼接
- Seata的
undo_log表禁止存明文PII,必须用HMAC-SHA256(uid, secret)生成脱敏ID
最麻烦的是权限最小化没落到物理节点:逻辑库shop_db配了只读,但攻击者直连shop_db_042就能绕过中间件管控——这要求每个物理库单独执行GRANT SELECT ON shop_db_042.users TO app_user。











