富文本必须先用bluemonday白名单清洗再转template.html:在handler层调用policy.sanitize()后立即转为template.html,禁止模板中使用safehtml;属性值、url、js上下文需额外校验,避免xss。

富文本必须先过 bluemonday,再转 template.HTML
直接把用户提交的 HTML 字符串包成 template.HTML 是最常见、也最危险的写法。哪怕你用了 html/template,一旦上游没过滤,<img src="https://img.php.cn/?x-oss-process=image/resize,p_40" alt="如何在 Golang 中安全处理来自非信任客户端的富文本字符串"> 这类内容就会原样输出执行。
正确路径只有一条:在 handler 层用 bluemonday 白名单策略清洗,清洗后才传给模板并标记为安全。
-
bluemonday.UGCPolicy()适合评论、文章等通用场景,允许a、strong、ul等标签,但默认禁掉所有on*事件和javascript:协议 - 别自己写正则删
onerror或href="javascript:——绕过方式太多,比如onmousemove=alert(1)//、JaVaScRiPt:都能逃逸 - 清洗后调用
policy.Sanitize(dirty)返回的是纯文本字符串,需显式转成template.HTML(clean)才能绕过模板自动转义
别在模板里写 {{.Raw | safeHTML}}
这个写法等于把过滤逻辑甩给模板层,而模板不具备上下文判断能力。它不关心你传进来的是不是已清洗过的 HTML,只负责“不转义”。
初始化并管理阿里云SDK Go 客户端,涵盖 sync.Once 单例、goroutine 安全、endpoint 与 region 配置、VPC 端点及调试。
后果是:如果某次 handler 忘记调用 bluemonday,或者清洗策略配置错误(比如用了 bluemonday.StrictPolicy() 却漏配了 iframe 的 src 白名单),XSS 就直接进来了。
- 所有
template.HTML构造必须发生在 handler 中,且紧挨着bluemonday.Sanitize()调用之后 - 模板中禁止出现任何自定义
safeHTML类型的 funcMap,避免形成“绕过开关” - 如果多个地方要用富文本,把清洗 + 转
template.HTML封装成一个函数,例如SanitizedHTML(input string) template.HTML,并在函数内部强制校验非空和合法性
属性值、URL、JS 上下文不能靠 bluemonday 兜底
bluemonday 只管 HTML DOM 结构,不管插入位置。如果你把用户输入塞进 <a href="https://www.php.cn/link/8627a5992a7f67f8c1e3db85cf9c23eb"></a> 或 <script>var url = "https://www.php.cn/link/8627a5992a7f67f8c1e3db85cf9c23eb";</script>,就算它本身是干净 HTML,也会因上下文错位触发 XSS。
-
href、src等属性值必须额外校验协议:拒绝javascript:、data:、vbscript:,只允许http://、https://、/、# - JS 内部变量必须用
json.Marshal输出到data-属性,前端再读取,而不是拼进<script></script>标签 - CSS
style属性禁止拼接用户输入;如需动态样式,提取结构化字段(如color、font-size)单独渲染
注意 bluemonday 的策略差异与性能开销
不同策略影响可渲染内容范围,也影响 CPU 和内存占用。线上服务高频调用时不能无脑用 UGCPolicy()。
-
bluemonday.UGCPolicy()允许iframe、embed,但默认禁掉其src,需手动加白名单:policy.AllowAttrs("src").OnElements("iframe") -
bluemonday.StrictPolicy()更安全,但会干掉所有样式和链接,不适合需要基础排版的场景 - 对同一段富文本反复清洗(比如列表页每项都调一次
Sanitize),建议缓存清洗结果,或用sync.Pool复用policy实例 - 若用户提交的是超长 HTML(如万字文章),
bluemonday解析 DOM 树会有明显延迟,可考虑前置截断(按 rune 数而非字节)再清洗
<a href="https://example.com" target="_blank" rel="noopener"></a> 缺少 rel="noopener" 会导致 window.opener 泄露。这不属于 XSS,但属于关联风险,得靠策略配置和人工 Review 补齐。golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!










