中间件无法拦截sql注入攻击,因其仅作用于http请求处理阶段,而sql注入发生在数据库执行层;真正防护必须在db.query()等sql调用处使用参数化查询或白名单校验。

中间件无法拦截SQL注入攻击——这不是中间件该干的事,也根本拦不住。
为什么SQL注入不能靠HTTP中间件拦截
SQL注入发生在数据库查询执行阶段,而HTTP中间件只在请求进入路由、参数解析、身份校验等环节起作用。它看到的只是原始字符串(比如 name=alice%27%20OR%20%271%27%3D%271),但完全不知道这段输入后续会被拼进哪条SQL、用什么方式拼、是否经过参数化处理。
- 中间件无法区分
"admin' -- "是普通用户名,还是准备塞进fmt.Sprintf("SELECT * FROM users WHERE name = '%s'", input)的炸弹 - 你可以在中间件里过滤单引号、分号、
UNION等关键词,但绕过方式极多(URL编码、大小写混写、注释符绕过),漏报率高、误杀率也高 - gosec、revive 等静态扫描工具都明确指出:
Raw()、Query()、Exec()调用必须人工审计,中间件 runtime 拦截属于幻觉防御
真正该拦截的地方:database/sql 和 GORM 的调用点
防护必须落在 SQL 执行前的最后一环——也就是你手写或 ORM 生成 SQL 的地方。重点盯死三类调用:
-
db.Query()/db.Exec()/db.QueryRow():必须带占位符,且占位符类型与驱动严格匹配(MySQL 用?,PostgreSQL 用$1) -
db.Prepare():和Query()安全性一致,仅影响执行计划复用,不改变防护能力 -
db.Raw()(GORM):这是高危接口,gosec -exclude=G201会直接标红;任何未用占位符的字符串拼接都等于裸奔
示例对比:
// ❌ 危险:中间件拦不住,运行时直接执行恶意SQL
db.Query("SELECT * FROM users WHERE name = '" + name + "'")
<p>// ✅ 安全:驱动层隔离数据与结构,中间件无需、也不能介入
db.Query("SELECT * FROM users WHERE name = ?", name)</p><p>// ❌ 危险:GORM Raw() 里拼表名,中间件看不到上下文
db.Raw("SELECT * FROM " + tableName + " WHERE id = ?", id).Scan(&u)</p><p>// ✅ 安全:白名单校验 + 占位符分离
if !validTableNames[tableName] { return errors.New("invalid table") }
db.Raw("SELECT * FROM ? WHERE id = ?", sql.Named("table", tableName), id).Scan(&u) // 注意:sql.Named 不适用于表名,此处仅为示意;实际必须白名单后字符串拼接</p>
中间件能做的有限但有用的事
它不能防注入,但可以辅助暴露问题、限制攻击面:
- 记录所有含可疑模式的请求(如
%27OR%271%3D1、UNION SELECT),用于安全监控和溯源 - 对已知高风险字段(如
order_by、limit)做白名单校验并提前拒绝,避免这些值流到 SQL 层再出错 - 强制设置
Content-Security-Policy等响应头,降低 XSS 配合 SQL 注入的横向危害(比如通过 XSS 窃取管理员 session 后发起注入)
真正关键的防护逻辑,永远在 db.Query 那一行代码里——不是之前,也不是之后。











