用golang.org/x/net/html解析并遍历节点比正则靠谱,因其按规范构建dom树,能正确处理实体、自闭合标签、注释及嵌套结构,支持白名单式安全重建,避免正则无法应对的编码、大小写混用等绕过方式。

用 golang.org/x/net/html 解析并遍历节点比正则靠谱
正则匹配 HTML 标签在 Go 里既不可靠又易绕过,比如 <img src="x" onerror="alert(1)"> 或注释中藏脚本,正则根本处理不了嵌套、编码、大小写混用等变体。必须用真正的 HTML 解析器,golang.org/x/net/html 是标准选择——它按规范解析 DOM 树,能识别实体、命名空间、自闭合标签等细节。
关键不是“删掉 script 标签”,而是白名单式重建:只保留你明确允许的元素和属性,其余一律丢弃或转义。例如 style 属性要额外校验值是否只含安全 CSS 声明,href 和 src 必须限制协议为 http://、https:// 或 #。
实操建议:
- 用
html.Parse()解析输入,捕获io.EOF和html.ErrNoEOF等常见错误,别让 malformed HTML 导致 panic - 遍历节点时对每个
*html.Node类型做 switch 判断:html.ElementNode、html.TextNode、html.CommentNode—— 注释节点应直接跳过,不渲染 - 对文本节点(
html.TextNode)不做 HTML 转义(那是输出时的事),保持原样;但若父节点是被禁止的容器(如script),整个子树应被忽略
policy.AllowAttrs 白名单必须显式声明每个属性的值校验逻辑
仅允许 class 或 id 属性还不够,攻击者可利用 onerror、onclick、data-*(配合框架漏洞)等注入行为。Go 的 bluemonday 库封装了策略模型,但底层逻辑得自己理清:每个属性都要配一个 policy.AttrPolicy 函数,返回是否放行及是否需要转义。
常见陷阱:
-
href允许javascript:协议?绝对不行。必须用strings.HasPrefix(val, "http://") || strings.HasPrefix(val, "https://") || val == "#"显式判断 -
style属性不能简单放行。需用css.Parse(如github.com/andybalholm/cascadia/css)或正则粗筛(如只允字母、数字、空格、括号、分号、冒号、点、逗号、连字符),否则expression(...)或url(javascript:...)会逃逸 -
data-属性默认全禁,除非业务强需且后端有对应校验。开启前务必确认前端框架不会将其当作指令执行
避免直接拼接字符串,用 html.Render 输出结果
清洗后的节点树仍是内存中的 *html.Node 结构,如果手动拼 "",可能遗漏属性转义、自闭合规则(如 br 不写 />)、或把 & 渲染成 & 造成双重编码。Go 标准库的 html.Render 会严格遵循 HTML5 规范做序列化。
使用要点:
- 创建
bytes.Buffer或strings.Builder作为输出目标,传给html.Render() - 确保清洗后根节点是
html.DocumentNode或html.ElementNode;若输入是片段(无),html.Render仍能正确输出纯 HTML 片段 - 不要对最终输出再调用
html.EscapeString()—— 这会让所有变成 <code><,破坏结构。清洗阶段已控制节点,渲染阶段只需忠实还原
注意 iframe、object、embed 这类富媒体标签的隐性风险
它们本身不执行 JS,但可加载外部内容(如恶意 HTML 页面),形成间接 XSS。即使 src 被限制为 HTTPS,也无法阻止服务端返回带脚本的响应。所以生产环境应默认禁止这些标签,除非有强理由且配合 CSP 头(frame-src)。
实操中容易漏的点:
-
iframe的sandbox属性看似安全,但若未显式禁用allow-scripts,仍可执行 JS;而 Go 清洗器无法验证 sandbox 值的有效性,只能当普通属性处理 -
object标签的type属性若为text/html,其子内容会被浏览器当作 HTML 解析 —— 即使你删了子节点,只要type存在就危险 - 某些旧版 IE 支持
behaviorCSS 属性,虽现代浏览器已废弃,但若需兼容老系统,清洗策略还得额外过滤style中含behavior:的声明
真正难的不是写一个能跑的清洗函数,而是持续跟踪新出现的绕过方式(比如 SVG 中的 <animate></animate> 标签触发 onload)、浏览器差异、以及业务场景中那些“必须留着但其实不安全”的妥协点。每次加白名单前,先问一句:这个标签/属性,在当前页面上下文中,有没有可能被用来触发执行?
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











