富文本必须用bluemonday白名单过滤而非正则清洗,UGCPolicy()配合URL协议校验、JS上下文安全插值及客户端DOMPurify二次净化,构成四层防护链。

富文本必须用 bluemonday 白名单过滤,不是正则清洗
正则表达式删 onerror= 或 javascript: 是无效的。攻击者可以用 onmousemove=alert(1)//、JaVaScRiPt:、javascript: 等方式绕过。bluemonday 先将 HTML 解析成 DOM 树,再按策略逐节点、逐属性裁剪,这才是可靠做法。
- 安装:
go get github.com/microcosm-cc/bluemonday - 用
bluemonday.UGCPolicy(),不是StrictPolicy—— 后者会清掉所有<strong>、<p>,实际业务没法用 - 过滤后仍需走
html/template渲染,不能fmt.Fprintf直接输出
template.HTML 是信任开关,不是过滤开关
你调用 template.HTML(p.Sanitize(input)) 并传入模板,只是告诉 html/template:“这段 HTML 我已确认安全”。它不会二次过滤,也不会拦截 <img src=x onerror=...> —— 如果 bluemonday 漏了,XSS 就进来了。
- 过滤逻辑必须在 handler 层完成,绝不能写成
{{.Content | safeHTML}}丢给模板判断 - 不要对原始用户输入直接包
template.HTML,比如template.HTML(r.FormValue("content"))是高危操作 - 哪怕用了
template.HTML,也得确保变量名是{{.CleanedHTML}}这类明确语义的字段,避免和未过滤字段混淆
URL 和事件属性必须额外校验,bluemonday 不覆盖全部
bluemonday.UGCPolicy() 默认允许 href、src,但它不检查协议合法性。用户填 javascript:alert(1) 或 data:text/html,<script>... 仍会通过。
Go 配置库,使用 spf13/viper — 分层优先级(flag > env >file > KV > default),提供 BindPFlag/BindPFlags、SetEnvPrefix + SetEnvKeyReplace 等功能。
- 对富文本中提取出的链接,用
net/url.Parse校验:只允许https?、/开头的相对路径 - 禁止保留
onerror、onclick等事件属性 ——UGCPolicy()默认已禁,但自定义策略时容易漏 - 若需支持跳转链接,建议统一走后端跳转中间页(如
/go?url=xxx),由服务端校验后再重定向
JS 上下文里别拼富文本,哪怕它已过滤
把过滤后的 HTML 字符串塞进 <script>var desc = "{{.CleanedHTML}}";</script> 是危险的。JS 引号逃逸、反斜杠处理、Unicode 编码都可能破坏语法并触发执行。
立即学习“Java免费学习笔记(深入)”;
- 需要前端读取富文本内容时,改用
data-属性 + JSON:<div data-desc="{{.CleanedJSON}}"></div>,其中CleanedJSON是json.Marshal后的结果 - 永远不要在
<script>内部插值 HTML 字符串;更不要用innerHTML直接赋值未再校验的内容 - 如果前端必须解析 HTML 片段,确保使用 DOMPurify 等客户端库做二次净化,不能只信服务端一次过滤
html/template 也不管,全靠开发者手动兜底。

















