直接c.html()渲染富文本会触发xss,因其不做过滤而原样输出含恶意脚本的html;须用bluemonday清洗后,再通过{{.content | safehtml}}输出。

为什么直接 c.HTML() 渲染富文本会触发 XSS?
富文本内容(比如用户通过 WangEditor 提交的 HTML)常含 <img src="...">,但攻击者可能混入 <img src="x" onerror="alert(1)"> 或 <script></script>。Gin 的 c.HTML() 不做任何过滤,原样输出到浏览器,只要服务端没清理,前端一解析就执行脚本。
用 bluemonday 预处理富文本再传给模板
不能依赖前端或模板引擎“自动转义”——html/template 的 {{.Content}} 默认是转义的,但富文本需要保留合法标签(如 <img>、<p></p>),所以必须在服务端清洗后,再用 {{.Content | safeHTML}} 输出。
- 安装:
go get github.com/microcosm-cc/bluemonday@v1.0.23(锁定次版本,避免策略变更) - 定义策略:用
bluemonday.UGCPolicy()允许<img>,但默认禁用onerror、onclick等事件属性 - 清洗时机:在组装
gin.H{}之前,对用户提交的富文本字段调用policy.Sanitize() - 模板里必须显式声明安全:用
{{.Content | safeHTML}},不能写{{.Content}}
// 示例:清洗并传入模板
policy := bluemonday.UGCPolicy()
policy.AllowAttrs("src", "alt", "width", "height").OnElements("img") // 显式放行 img 的这几个属性
cleanContent := policy.Sanitize(userSubmittedHTML)
c.HTML(http.StatusOK, "detail.tmpl", gin.H{
"Content": template.HTML(cleanContent), // 转为 template.HTML 类型
})
<img> 标签的安全属性控制要点
即使用了 bluemonday,也要主动限制 <img> 的行为,否则仍可能被用于 CSRF 或信息泄露:
-
src必须校验协议:只允许https://、/static/或已知 CDN 域名(如cdn.example.com),拒绝javascript:、data:、file: -
crossorigin属性建议强制设为anonymous,避免跨域图片读取失败时暴露敏感头 - 禁止
usemap、ismap、longdesc等低频且易被滥用的属性 - 宽度/高度应有合理上限(如
width),防止页面布局崩坏
模板里别漏掉 safeHTML 这个关键过滤器
Gin 默认不注册 safeHTML,得自己加:
r.SetFuncMap(template.FuncMap{
"safeHTML": func(s string) template.HTML {
return template.HTML(s)
},
})
然后模板中必须这么写:
{{.Content | safeHTML}}
如果忘了这一步,或者误写成 {{.Content | html}}(这是转义函数,会把 <img> 变成纯文本),富文本就完全失效了。这个点最容易被忽略,尤其在多人协作时,有人改了清洗逻辑,但没同步更新模板调用方式。











