SQL注入防护必须下沉到数据库驱动层而非HTTP中间件,因中间件无法获知最终执行的SQL;正确做法是patch sql.Conn或包装driver.Stmt,在Query/Exec前校验预编译语句合法性。

中间件里根本拦不住真实SQL注入
在 Fiber 的 HTTP 中间件里做 SQL 注入检测,本质是徒劳的——因为此时请求还没进 DAO 层,你根本不知道最终执行的 SQL 是什么。cursor.execute() 那行代码在业务 handler 里,中间件只看到 id=1%27%20OR%201%3D1 这种原始参数,但无法判断它会不会被拼进 fmt.Sprintf("SELECT * FROM user WHERE id = %s", id)。更糟的是,MyBatis、GORM 或 raw database/sql 的行为完全不经过中间件。
- 中间件能拿到的只有 URL 参数、Header、Body 字符串,没有 SQL 上下文
- 所有基于关键词(
UNION SELECT、' OR 1=1)的正则匹配都容易误杀(比如用户名含O'Reilly)或漏掉编码绕过(%27、%00、/**/) - 若强行解析 JSON Body,必须用
ContentCachingRequestWrapper类似机制缓存流,否则后续 handler 读不到数据
真正该拦截的位置:数据库驱动层
Fiber 本身不封装数据库逻辑,所以防护点必须下沉到 sql.DB 的 Query/Exec 调用入口。推荐做法是 monkey patch *sql.Conn 或包装 driver.Stmt,在真正执行前检查 query 字符串是否含用户输入变量。
- 注册时机必须在每次获取新连接后,不能只 patch 初始化时的
db对象——连接池会复用连接,中间件 hook 一次就失效 - 检测逻辑应拒绝任何含
%s、+、fmt.Sprintf拼接痕迹的原始 SQL,抛出SecurityError: raw SQL with interpolation detected - 允许的唯一安全模式是带占位符的预编译语句:
db.Query("SELECT * FROM users WHERE id = ?", id)
如果你非要加一层 HTTP 请求筛查
可以作为辅助手段,但仅限高危路径(如 /api/search、/admin/login),且动作设为「记录+放行」而非拦截。重点不是拦住,而是快速发现异常模式。
- 只扫描
c.Queries()和c.Body(),跳过Content-Type: application/json的 body 解析(避免流重复读) - 用严格模式匹配:比如
'\s+(?:or|and)\s+1\s*=\s*1,而非宽泛的OR 1=1(否则filter=ORANGE也被拦) - 必须先做 URL 解码再校验,否则
%27OR%201%3D1直接逃逸 - 禁用 HTML 实体转义或删
UNION关键字——合法数据(如产品名UNION Carbide)会被破坏
最不该做的三件事
这三类操作在 Fiber 项目里高频出现,但全是无效防御,还会引入新问题。
- 在中间件里对
$_GET或c.FormValue()做htmlspecialchars()—— 这防的是 XSS,跟 SQL 注入无关,还可能把二进制参数(如 base64 图片)搞坏 - 写个全局
func sanitizeSQL(s string) string然后到处调用 —— 输入净化不能代替参数化查询,攻击者绕过方式太多 - 依赖 WAF 规则
args contains "union"就以为万事大吉 —— 没启用libinjection_is_sqli语义引擎的 WAF,对变形 payload 几乎无感
真正的防护边界在 database/sql 的 Stmt.Exec 调用那一瞬间,而不是 HTTP 请求抵达 Fiber 的那一刻。别在错误的地方堆逻辑。


















