富文本必须用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></strong>、<p></p>,实际业务没法用 - 过滤后仍需走
html/template渲染,不能fmt.Fprintf直接输出
template.HTML 是信任开关,不是过滤开关
你调用 template.HTML(p.Sanitize(input)) 并传入模板,只是告诉 html/template:“这段 HTML 我已确认安全”。它不会二次过滤,也不会拦截 <img src="x" onerror="..."> —— 如果 bluemonday 漏了,XSS 就进来了。
Go 配置库,使用 spf13/viper — 分层优先级(flag > env >file > KV > default),提供 BindPFlag/BindPFlags、SetEnvPrefix + SetEnvKeyReplace 等功能。
- 过滤逻辑必须在 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>...</script> 仍会通过。
- 对富文本中提取出的链接,用
net/url.Parse校验:只允许https?、/开头的相对路径 - 禁止保留
onerror、onclick等事件属性 ——UGCPolicy()默认已禁,但自定义策略时容易漏 - 若需支持跳转链接,建议统一走后端跳转中间页(如
/go?url=xxx),由服务端校验后再重定向
JS 上下文里别拼富文本,哪怕它已过滤
把过滤后的 HTML 字符串塞进 <script>var desc = "{{.CleanedHTML}}";</script> 是危险的。JS 引号逃逸、反斜杠处理、Unicode 编码都可能破坏语法并触发执行。
- 需要前端读取富文本内容时,改用
data-属性 + JSON:<div data-desc="{{.CleanedJSON}}"></div>,其中CleanedJSON是json.Marshal后的结果 - 永远不要在
<script></script>内部插值 HTML 字符串;更不要用innerHTML直接赋值未再校验的内容 - 如果前端必须解析 HTML 片段,确保使用 DOMPurify 等客户端库做二次净化,不能只信服务端一次过滤
html/template 也不管,全靠开发者手动兜底。Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










