中间件不应过滤SQL注入特征,因其无法识别SQL上下文且易被绕过;它应专注结构化参数校验:排序字段白名单、租户表前缀映射、IN子句ID预解析。

中间件不能统一过滤 SQL 注入特征——这不是它的职责,也做不到真正安全。
为什么中间件层做“SQL 特征过滤”是无效且危险的
SQL 注入不是靠字符串里有没有 '、UNION 或 -- 来判断的。攻击者用十六进制编码(0x27)、宽字节、注释嵌套(/* */)、大小写混用(SeLeCt)就能绕过所有基于字符的“清洗”。更关键的是:中间件看到的只是 HTTP 请求体或查询参数,它根本不知道这些数据最终会拼进哪条 SQL、以什么上下文使用。
- 用户传
sort=score%20ASC%20--,中间件删掉--,但后端若直接拼进ORDER BY ?就 panic;真要拼,删了也没用——因为ORDER BY本就不能参数化 - API 接收
table_name=user_logs_2024,中间件放行,后端却用fmt.Sprintf("SELECT * FROM %s", table)—— 过滤毫无意义 - 把
html.EscapeString或url.QueryEscape塞进中间件,只会让合法输入存成乱码,还掩盖真实问题
中间件真正该做的三件事
中间件不是 SQL 防御前线,而是校验和收敛入口。它只处理那些「必须在 DAO 层之前确定」的结构型参数:
-
排序字段白名单拦截:检查
sort参数是否在map[string]bool{"created_at": true, "status": true}中,不在就直接http.Error -
分表/租户标识映射:把
tenant=prod映射为固定表前缀users_prod,而不是放任后端拼"users_" + tenant -
IN 子句 ID 列表预解析:对
ids=1,2,3提前转成[]int64并校验每个值是否为正整数,空或非法值直接拒掉——避免 DAO 层拿到字符串后手拼"IN (" + idsStr + ")"
GORM / database/sql 的 Raw() 调用必须绕过中间件校验
中间件无法识别 db.Raw("SELECT * FROM users WHERE name = ?", name) 是安全的,也无法识别 db.Raw(fmt.Sprintf("SELECT * FROM %s", table)) 是裸奔。这类逻辑必须在 DAO 层硬编码约束:
立即学习“go语言免费学习笔记(深入)”;
- 所有
db.Raw()调用必须人工审计,禁止出现+、fmt.Sprintf、strings.Join等拼接操作 - 涉及动态表名时,强制走
switch table { case "user": return "users_v2" },而非字符串拼接 - 用
sqlx.In处理IN子句:先调query, args, _ := sqlx.In("SELECT * FROM u WHERE id IN (?)", ids),再db.Query(query, args...)
最常被忽略的一点:空切片传给 IN 会生成 IN () 导致语法错误,而中间件不会帮你 catch 这个——必须在 DAO 层显式判断 len(ids) == 0 并返回空结果或报错。


















