Buffalo中富文本渲染需全链路防护:服务端用bluemonday清洗、字段命名加Safe前缀、模板用{{ .SafeContent | safe }}、禁用plush的html函数、CI检查误用。

Buffalo模板中直接使用r.HTML会触发XSS风险
Buffalo默认用plush模板引擎,所有变量插值({{ .Content }})默认是HTML转义的,但一旦你显式调用r.HTML或在模板里写{{html .Content}},就等于告诉框架“这段内容可信”,绕过所有转义——如果.Content来自用户输入(比如富文本编辑器提交的<script>alert(1)</script>),就会直接执行。
必须用plush内置safe函数配合白名单过滤
Buffalo不提供开箱即用的富文本 sanitizer,safe只是取消转义,不能替代过滤。你得自己加一层防护:
- 引入
github.com/microcosm-cc/bluemonday或github.com/grokify/html-strip做服务端清洗,在Action里处理:func ArticleShow(c buffalo.Context) error { article := &Article{} // ... 加载 article.Content policy := bluemonday.UGCPolicy() // 只允许常见富文本标签 article.SafeContent = template.HTML(policy.Sanitize(article.Content)) return c.Render(200, r.HTML("article.html")) } - 模板里必须用
{{ .SafeContent | safe }},不能用{{ .Content }}或{{html .Content}} - 别依赖前端
DOMPurify做唯一防护——Buffalo服务端渲染时已输出原始HTML,客户端JS再处理为时已晚
禁用plush的html函数避免误用
plush模板自带html函数(等价于safe),但它没有上下文校验,极易被开发者随手写成{{html .UserInput}}。最稳妥的做法是在app.go里删掉它:
app.Templates = plush.New(plush.Options{
Funcs: plush.FuncMap{
// 不注册 "html" 函数
"safe": func(s string) template.HTML { return template.HTML(s) },
},
})
这样模板里写{{html .X}}会直接报错function "html" not defined,强制你走显式、带注释的SafeContent字段路径。
立即学习“前端免费学习笔记(深入)”;
富文本字段命名必须带Safe前缀并文档化
这是最容易被忽略的协作陷阱:团队成员看到.Content字段,可能下意识认为它已安全。解决方案很直白:
- 所有经
bluemonday清洗后的字段,变量名必须含Safe,如SafeDescription、SafeBody - 在struct定义上方加注释:
// SafeContent is sanitized via bluemonday.UGCPolicy() before rendering. // Never render .Content directly. type Article struct { Content string `json:"content"` SafeContent template.HTML `json:"-"` // not serialized } - CI阶段加检查:
grep -r '\.Content.*html' ./templates/,发现就失败
富文本渲染不是“开了safe就万事大吉”,而是从字段命名、清洗时机、模板调用到CI检查的全链路约定。漏掉任意一环,XSS漏洞就在那里等着。



















