Revel框架不内置ORM且不默认防SQL注入,必须手动使用database/sql预处理语句(如Query/QueryRow带?或$1占位符)、严格校验动态字段(白名单)、避免字符串拼接,方可有效防御。

Revel 框架本身不内置 ORM,也不自动封装参数化查询逻辑,所以它**不会像 Laravel 或 Django 那样“默认防 SQL 注入”**。能否防住,完全取决于你用什么数据库驱动、怎么写查询、是否手动绑定参数。
Revel 里直接用 database/sql + 预处理语句才是正解
Revel 是 Go 写的,底层依赖 database/sql 标准库。只要你不拼接字符串,而是用 Query / QueryRow / Exec 的参数化接口,就能天然防注入。
- ✅ 正确写法:占位符用
?(MySQL)或$1(PostgreSQL),参数单独传入 - ❌ 危险写法:
"SELECT * FROM users WHERE name = '" + name + "'"—— Revel 不会拦截或重写这种字符串拼接 - ⚠️ 注意驱动差异:MySQL 驱动(
github.com/go-sql-driver/mysql)只支持?;PostgreSQL 驱动(github.com/lib/pq)只支持$1、$2;不能混用 - 性能上无额外开销:预处理在连接池中可复用,
Prepare调用一次后,后续Query只传参,不重解析 SQL
Revel 控制器里别碰 raw SQL 字符串拼接
常见翻车点是:想动态加 WHERE 条件、排序字段或 LIMIT 偏移量,就手写字符串拼接。这类场景必须拆解——可变部分走白名单校验,固定部分走参数绑定。
- 列名/表名/ORDER BY 字段:不能用参数占位符,必须提前定义白名单,比如
map[string]bool{"name": true, "created_at": true},再做if !allowedCols[col] { return error } - LIMIT/OFFSET:Go 的
int类型可直接传,但需先检查非负、有上限(如if n 1000 { ... }) - IN 查询:不能写
WHERE id IN (?)并传 slice;得动态生成?, ?, ?占位符,再展开 slice 为参数列表(可用sqlx.In或手写strings.Repeat)
Revel + GORM 或 sqlx 能省力但不免责
用 GORM 或 sqlx 是常见选择,它们封装了预处理和结构体映射,但防注入能力仍取决于你调用方式。
- GORM 的
Where("name = ?", name)安全;Where("name = " + name)或Where("name = " + r.Params.Get("name"))直接崩盘 - sqlx 的
Get(&u, "SELECT * FROM users WHERE id = ?", id)安全;但NamedQuery若模板里含用户输入变量(如SELECT * FROM :table),照样被绕过 - 所有框架都管不了日志打印:别在
log.Printf("query: %s, args: %v", sql, args)里把原始 SQL 和用户输入一起打出来,容易泄露 payload 或触发二次注入分析
最易被忽略的是:Revel 的 Params 和 Flash 数据全程未过滤,你取出来就用,等于把攻击面直接暴露给数据库层。防注入不是加个中间件就能完事的事,它从路由参数解析那一刻起,就得带着“这个值接下来要进哪条 SQL”的意识来处理。











