应使用 bluemonday 预设策略(如 strictpolicy 或 ugcpolicy)定义白名单,而非正则清洗;清洗须在 handler 层完成,禁止模板中直接 safehtml;纯文本需求应避免 bluemonday,改用 goquery.text 等健壮方式提取。

用 bluemonday 定义白名单策略,而不是写正则清洗
正则清洗 HTML 是典型陷阱:比如删 on\w+=,但 onmousemove=alert(1)//、JaVaScRiPt:、javascript: 都能绕过。bluemonday 基于白名单,只保留你明确允许的标签和属性,其余一律剥离。
别自己拼 bluemonday.NewPolicy() 从零配置,优先用预设策略:
-
bluemonday.StrictPolicy():彻底清空所有标签,只留纯文本 —— 适合评论摘要、搜索结果预览 -
bluemonday.UGCPolicy():允许<p></p>、<strong></strong>、<ul></ul>、<li>等常见排版标签,禁用所有事件属性(onclick、onerror)和危险协议(javascript:、data:) - 需要支持图片?在
UGCPolicy()基础上加.AllowAttrs("src").OnElements("img")
把清洗逻辑放在 handler 层,别塞进模板里
常见错误是模板里写 {{.RawHTML | safeHTML}},再靠前端或中间件“事后过滤”。这等于把安全责任甩给不可控环节 —— 一旦上游漏掉一次清洗,XSS 就落地了。
初始化并管理阿里云SDK Go 客户端,涵盖 sync.Once 单例、goroutine 安全、endpoint 与 region 配置、VPC 端点及调试。
正确做法:在 HTTP handler 中完成清洗,再传入 template:
- 接收表单数据后立即调用
policy.Sanitize(input) - 清洗结果赋值给结构体字段,例如
Post.Content = policy.Sanitize(r.FormValue("content")) - 模板中仍用
{{.Content}},由html/template自动转义;若确认已清洗干净,才用template.HTML(cleaned)插入 - 注意:
template.HTML不做任何校验,它信任你传进去的就是安全 HTML
区分「纯文本提取」和「富文本清洗」两种需求
不是所有场景都要保留 HTML 标签。如果只是想取用户输入的纯文字内容(比如用于日志分析、全文检索、短信通知),就不要走 bluemonday 流程,直接用更轻量的方式:
- 简单去标:用
regexp.MustCompile(`]+>`).ReplaceAllString(raw, "")—— 仅适用于无嵌套、无属性的极简 HTML - 健壮去标:用
goquery解析后取文本节点:doc.Find("body").Text(),能正确处理<script></script>、<style></style>和实体编码 - 警惕
strings.ReplaceAll(html, " 这类粗暴替换 —— 会破坏含 <code> 的合法文本(如数学公式 <code>a )
注意 bluemonday 的线程安全与初始化开销
bluemonday.Policy 对象是只读且线程安全的,但创建 Policy 实例本身有开销。别在每次请求里 new 一个:
- 全局定义一次:
var ugcPolicy = bluemonday.UGCPolicy() - 在 handler 中复用:
clean := ugcPolicy.Sanitize(userInput) - 若需自定义策略,也应在 init 或 main 中构建完成,而非 request scope 内重复调用
NewPolicy() - 对性能敏感的服务,可考虑用
sync.Pool缓存bytes.Buffer等中间对象,但 Policy 本身不需要池化
<blockquote></blockquote> 触发栈溢出),所以要配合输入长度限制和响应体大小控制。golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!










