Revel模板默认不自动转义,XSS风险由开发者承担;必须显式使用esc函数对HTML内容体转义,但esc不适用于属性值、URL或JavaScript上下文,需配合url.QueryEscape()、js.Marshal()等分层防护。

Revel 框架模板默认不安全——它不自动转义,XSS 风险完全由开发者承担。这不是 bug,而是设计选择:把控制权交给你,但代价是极易漏掉 esc 或误用 raw。
为什么 Revel 模板容易触发 XSS
Revel 使用自研模板引擎,和 Go 标准库的 html/template 有本质区别:它不会根据上下文自动判断该用哪种转义。比如 {{.UserName}} 会原样输出,若值为 <script>alert(1)</script>,浏览器立刻执行。而 html/template 在同样位置会自动转义成文本。常见错误现象包括:用户昵称里嵌入 <img src=x onerror=alert(1)> 后所有访客弹窗;评论区显示“已过滤”但实际脚本仍运行。
必须用 esc 函数,且仅适用于 HTML 内容体
esc 是 Revel 唯一内置的安全转义函数,等效于 html.EscapeString(),只处理 <、>、&、"、' 五个字符。
- 正确写法:
{{esc .Title}}→ 安全插入<div>Hello</div>作为纯文本 - 错误写法:
{{.Title}}或{{.Title | esc}}(管道语法在 Revel 中不生效) - 注意:
esc不适用于属性值中的单引号闭合场景(如onclick='{{esc .Handler}}'),它不转义十六进制',推荐统一用双引号属性 +esc
raw 函数等于主动关闭防护,仅限可信富文本
raw 完全绕过转义,传入什么就渲染什么。一旦后端未净化或前端传入恶意内容,XSS 立即触发。
立即学习“go语言免费学习笔记(深入)”;
- 仅当满足全部条件时才可考虑:
raw的数据来自后台严格净化(如经bluemonday过滤的 HTML)、非用户直输、且无动态拼接 - 禁止在模板中混用:
{{raw .A}}{{.B}}—— 若.B未esc,整个输出链失效 - 更安全的替代:在控制器中提前组合并转义,再传一个已处理好的字段给模板,避免模板内逻辑复杂化
URL 和 JavaScript 上下文必须额外编码
esc 对 href、src、onclick 等属性完全无效。例如 href="{{esc .Url}}" 无法阻止 javascript:alert(1) 执行。
- URL 参数必须用
url.QueryEscape()处理,再传入模板:url := url.QueryEscape(userInput)→href="/search?q={{.Url}}" - JavaScript 字符串需在控制器中用
js.Marshal()编码,不能依赖模板函数 - 绝对不要写:
onclick="doSomething('{{esc .Data}}')"—— 这里需要的是 JS 字符串转义,不是 HTML 转义
最常被忽略的一点:Revel 没有上下文感知,esc 不是万能解药。你在属性里用它、在 URL 里用它、在 JS 里用它,都可能失效。真正的安全来自分层——输入校验 + 控制器预处理 + 模板正确函数 + CSP 响应头缺一不可。


















