Iris框架本身不防SQL注入,防御完全取决于开发者是否正确使用database/sql的参数化查询;必须用?或$1占位符绑定参数,严禁字符串拼接,且表名、字段名、排序等动态结构需白名单校验。

Iris 框架本身不防 SQL 注入,防注入靠的是你用 database/sql 的方式是否正确——和 Iris 无关,只和你怎么调用 db.Query、db.Exec 有关。
为什么 Iris 不能“自动”防注入
Iris 是 HTTP 路由与响应框架,它不接管数据库操作。你用 iris.Context 拿到参数后,最终执行查询的还是 sql.DB 或 GORM 等底层驱动。Iris 只负责把 ctx.URLParam("id") 或 ctx.FormValue("name") 交给你,之后拼 SQL 还是参数化,全在你手里。
常见翻车点:
- 写
db.Query("SELECT * FROM users WHERE id = " + ctx.URLParam("id"))—— 直接裸奔 - 用
fmt.Sprintf("UPDATE logs SET msg='%s'", ctx.FormValue("msg"))—— 单引号转义毫无意义 - 以为 Iris 自带 ORM 或 SQL 安全层 —— 它没有
必须用 ? 或 $1 占位符,不能混用驱动语法
MySQL/SQLite 驱动用 ?,PostgreSQL 驱动用 $1、$2。写错不会报错,但参数会被忽略,查不到数据或匹配字面量 $1。
示例(MySQL 场景):
// ✅ 正确:占位符 + 参数分离
id := ctx.URLParamIntDefault("id", 0)
rows, err := db.Query("SELECT name, email FROM users WHERE id = ?", id)
<p>// ❌ 错误:拼字符串(哪怕加了单引号)
query := "SELECT * FROM users WHERE id = '" + ctx.URLParam("id") + "'"
rows, err := db.Query(query)</p><p>// ❌ 错误:PostgreSQL 语法误用于 MySQL
rows, err := db.Query("SELECT * FROM users WHERE id = $1", id) // MySQL 驱动会忽略 $1,查所有行
</p>
ORDER BY / 表名 / 字段名必须白名单校验
db.Query("SELECT * FROM users ORDER BY ?", ctx.URLParam("sort")) 会 panic:sql: expected 0 arguments, got 1。SQL 标准规定这些属于查询结构,无法参数化。
真正该做的:
- 排序字段:定义合法值
map[string]bool{"created_at": true, "score": true, "name": true},查不到就拒掉 - 排序方向:只接受
"ASC"或"DESC",别信strings.ToUpper(ctx.URLParam("dir"))后直接拼 - 表名映射:用
switch或常量,比如tenantID == "prod" → "users_prod",禁用"users_" + tenantID
GORM 在 Iris 中也得小心 Raw() 和 IN 子句
很多人以为用了 GORM 就高枕无忧,其实 Raw() 和手动拼 IN 是重灾区:
-
db.Raw("SELECT * FROM users WHERE name = ?", name)✅ 安全 -
db.Raw("SELECT * FROM " + tableName + " WHERE id = ?", id)❌ 裸奔(tableName来自用户) -
db.Exec("UPDATE users SET status = ? WHERE id IN (" + idsStr + ")", status)❌ 若idsStr = "1, (SELECT password FROM admins)",直接触发注入 - ✅ 正确做法:
db.Where("id IN ?", idsSlice).Update("status", status),让 GORM 自动展开占位符
复杂点在于:白名单校验、占位符绑定、IN 子句展开这三步缺一不可;最容易被忽略的是「表名/字段名不可参数化」这个硬限制,一踩就中。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











