Revel框架防SQL注入须禁用DB.Raw拼接,强制使用DB.Query/Find配合?占位符实现参数化查询;动态表名等标识符必须白名单校验;模板输出需显式转义或改用html/template解析器。

Revel框架里SQL注入怎么防:别碰DB.Raw,优先用Query和Find
Revel本身不自带ORM,但默认集成database/sql,所有数据库操作都依赖你写的SQL或封装层。这意味着它不会像Laravel或Django那样自动帮你绑定参数——防注入完全靠你写法是否规范。
常见错误是看到DB.Raw("SELECT * FROM users WHERE name = '" + name + "'")就直接用,这等于把门敞开。Revel的DB.Raw不做任何转义,传进去什么就执行什么。
- 必须用
DB.Query或DB.Find配合占位符:例如DB.Query("SELECT * FROM users WHERE email = ?", email),底层走的是sql.Stmt预编译,参数始终作为数据传入 - PostgreSQL用户注意:
$1, $2占位符只在DB.Query中生效;若误用DB.Raw("... $1"),Revel不会帮你替换,会原样发给数据库报错 - 避免手写
fmt.Sprintf拼接SQL:哪怕加了strings.ReplaceAll去单引号也没用,绕过方式太多(比如用char(39)或编码) - 如果非要用
DB.Raw(比如动态表名),必须白名单校验:用map[string]bool{"users": true, "posts": true}查表名是否合法,绝不接受用户输入直接进SQL
模板里输出用户数据时,{{.Content}}默认不转义,必须手动处理XSS
Revel的模板引擎(基于Go html/template)本身是安全的,但有个关键前提:你得用对模板类型。默认app/views/xxx.html是text/template,它不自动转义;只有显式声明为html/template才启用HTML上下文转义。
也就是说,{{.UserInput}}在普通HTML视图里会原样输出,<script>alert(1)</script>直接执行。
- 最简单做法:把视图文件后缀从
.html改成.html.tmpl,并在app/init.go中注册时指定html/template解析器 - 或者保留
.html,但在输出时强制调用转义函数:{{.UserInput | html}}(Go标准库html函数) - 富文本场景不能全转义?那就用
template.HTML类型包装,但前提是已用bluemonday或go-sanitize做过净化,否则等于放行XSS - 千万别用
{{printf "%s" .UserInput}}这类绕过方式——它等价于未转义
HTTP头和中间件要补上,光靠模板和SQL不够
Revel没有开箱即用的CSP或X-XSS-Protection中间件,这些得自己加。很多团队只修了SQL和模板,上线后还是被反射型XSS打穿,问题就出在这层缺失。
- 在
app/init.go的init()里注册全局中间件:revel.Intercept((*App).SecurityHeaders, revel.BEFORE) -
SecurityHeaders方法里手动设头:c.Response.Out.Header().Set("Content-Security-Policy", "default-src 'self'; script-src 'self' 'unsafe-inline'")(注意:开发期可加unsafe-inline,上线前必须删掉) - Cookie必须带
HttpOnly和SameSite=Strict:revel.SessionOptions = &revel.SessionOptions{Cookie: &http.Cookie{HttpOnly: true, SameSite: http.SameSiteStrictMode}} - 错误页面别暴露SQL细节:重写
app/errors/500.html,生产环境禁用revel.Config.BoolDefault("app.show_errors", false)
为什么MyBatis或Hibernate能“自动防注入”,而Revel不行
因为MyBatis的#{}、Hibernate的JPQL、Django的filter()本质都是**查询抽象层**,它们在生成最终SQL前就完成了参数绑定逻辑。Revel的DB模块只是database/sql的薄封装,没做这层抽象——它把“怎么安全”交还给了开发者。
这带来两个现实后果:
- 团队里只要有一个人写
DB.Raw拼接,整个应用SQL注入风险就回归到原始水平 - Code review时必须盯死所有
DB.调用点,不能只扫SELECT关键字——攻击者早就不靠UNION SELECT了,时间盲注、DNS外带一样能拿数据
真正卡住风险的不是工具,是每次写SQL前那0.5秒的停顿:我这儿用的是?还是+?


















