中间件无法拦截SQL注入,因其运行在HTTP层而SQL注入发生在数据库驱动执行阶段;真正防护需下沉至database/sql底层,hook sql.Conn.QueryContext等方法,对所有发往数据库的原始SQL字符串进行检查。

中间件无法拦截SQL注入,这是根本性误解
Echo 框架的中间件(middleware)运行在 HTTP 请求处理链中,而 SQL 注入发生在数据库驱动执行阶段——两者不在同一层。你在 echo.MiddlewareFunc 里拿到的是 *echo.Context,它不接触 db.Query() 或 stmt.Exec() 这类调用。试图在中间件里“扫描请求参数是否含 UNION SELECT”纯属无效:攻击者改用注释绕过、大小写混淆、URL 编码,或直接从定时任务/CLI 脚本发起未走 Echo 的查询,中间件完全看不见。
真正该 hook 的位置是 database/sql 驱动入口
Go 生态下唯一可靠的防护点,是拦截所有实际发往数据库的原始 SQL 字符串。这必须下沉到 database/sql 底层,而非框架层。
- 重写
sql.Conn.QueryContext()方法,在执行前检查query字符串是否含${、+、fmt.Sprintf痕迹,或 AST 解析出变量插值结构 - 对连接池(如
sql.Open("postgres", ...))生成的每个*sql.Conn都做 patch,不能只 hook 初始化时的*sql.DB - 若用
pgx/v5,需 monkey patchpgxpool.Pool.Query();若用gorm,必须禁用Session.WithContext()以外的所有裸 SQL 执行路径
为什么 ORM 不等于安全,尤其在 Echo 项目中
很多 Echo 项目混用 gorm.Raw() 或 sqlx.MustExec(),这些调用绕过 GORM 的参数化逻辑,直接透传拼接字符串。更危险的是:Echo 中间件常被用于鉴权或日志,开发者误以为“加了 JWT 校验就安全了”,结果在 resolver 或 handler 内部随手写了 db.Query(fmt.Sprintf("SELECT * FROM %s WHERE id = %d", table, id)) —— 这种代码在中间件里永远检测不到。
Echo框架 5.1.0 版本源码包下载,适合关注 RealIP 行为变化、StartConfig.Listener、NewDefaultFS 和观测性中间件入口的开发团队。
-
gorm.Raw()、sqlx.MustExec()、database/sql.Stmt.Prepare()后的Exec()若传入拼接字符串,即刻失效 - 表名、排序字段(
ORDER BY ?)、分页偏移(LIMIT ?,?)无法用参数化,必须用白名单校验,比如map[string]bool{"created_at": true, "name": true} - CLI 脚本、MQ 消费器、Seata 补偿逻辑若复用同一套 DB 连接池,但没加载驱动层 hook,就是明确的漏洞盲区
Echo 项目里最容易被忽略的三个高危点
防御失效往往不是因为没做,而是做了但漏掉了关键路径。
- GraphQL 接口桥接
gqlgen时,resolver 内部直连 DB,且常绕过 Echo 中间件链——这里必须单独部署驱动层 hook - 使用
echo.Group()分路由后,某些子路由(如/admin/export)可能跳过主鉴权中间件,但导出逻辑仍会拼 SQL - 测试环境用
sqlite,生产切postgres,而 hook 只作用于前者,后者完全裸奔
真正起作用的防护,从来不在 Echo 的 echo.New().Use(...) 里,而在你 import _ "yourproject/dbhook" 的那个 init 函数中。那才是 SQL 执行前的最后一道门。

















