参数化查询是sql注入防护唯一有效手段,其他如全局过滤、关键词拦截均为辅助且易被绕过;动态表名/列名等无法参数化部分必须严格白名单校验,禁止字符串拼接。

参数化查询是唯一有效的防线,其他都是临时补丁
在Iris MVC中,SQL注入防护不靠中间件拦截、不靠关键词过滤,只靠参数化查询本身。任何试图用ctx.URLParam("id")取值后拼进SQL字符串的行为——比如"SELECT * FROM users WHERE id = " + id——都等于裸奔。EF Core的FromSqlRaw或原生database/sql的QueryRow(sql, args...)才是正路,且必须显式传参,禁用fmt.Sprintf和strings.Replace类字符串操作。
动态表名/字段名必须走白名单校验
Iris不提供SQL语法解析器,所以ORDER BY字段、WHERE条件中的列名、甚至FROM子句的表名,如果来自用户输入(如c.URLParam("sort")),参数化查询完全无效。此时只能硬编码白名单:
validSortFields := map[string]bool{"name": true, "email": true, "created_at": true}
if !validSortFields[sortInput] {
return c.StatusCode(400).Text("invalid sort field")
}
别用strings.Contains或正则模糊匹配——user_name和username语义不同,必须精确控制。
控制器里用依赖注入获取DB实例,但查询仍要手动参数化
Iris的app.RegisterController能自动注入*sql.DB或*gorm.DB,但这只是把连接池交到你手上,不等于自动防注入。常见错误包括:
- 在控制器方法里调用
db.Query("SELECT * FROM users WHERE status = '" + status + "'")——即使db是注入的,照样中招 - 用
db.Where("status = ?", status).Find(&users)是对的,但若写成db.Where("status = " + status).Find(&users)就退化为拼接 - 分页参数
c.URLParamInt("page")转成整型后,仍需确保后续Limit()/Offset()调用走ORM原生方法,而非手拼"LIMIT " + strconv.Itoa(size)
全局过滤器不能替代参数化,还容易引发静默失败
有人想在OnRequest中间件里统一过滤所有ctx.FormValue或ctx.URLParam,这是危险的:
- 解码不全:没调
url.QueryUnescape就过滤,%27OR%201%3D1直接漏过 - 误杀合法字段:
"select"作为用户名、"order"作为订单号会被干掉 - 破坏请求流:在中间件里读
ctx.Request().Body会消耗流,导致后续控制器收不到JSON数据 - 绕过简单:攻击者改用
UNION/**/SELECT或sel/*abc*/ect就能跳过基础正则
真要加日志型检测,只做记录+告警,别做阻断;核心逻辑永远压在参数化查询上,别的都是辅助。
最常被忽略的一点:Iris MVC本身不碰SQL,它只负责把请求参数交给控制器。防注入的责任完全落在你写的查询语句上——哪怕用了依赖注入、JWT鉴权、Session管理,只要有一处db.Query(fmt.Sprintf(...)),整个应用就存在高危漏洞。











