当前位置: 首页 > backend >正文

Go 剥离 HTML 标签的三把「瑞士军刀」——从正则到 Bluemonday

1 为什么要「剥皮」?

  • 安全:去掉潜在的 <script onload=…> 等恶意标签,防止存储型 XSS。
  • 可读性:日志、消息队列、搜索索引里往往只需要纯文本。
  • 一致性:不同富文本编辑器生成的 HTML 五花八门,统一成「干净文本」更好比对与检索。

2 三种主流方案

方案依赖适用场景优势局限
方案 A:一行正则临时脚本、CLI 工具最短代码、零依赖正则难以 100 % 解析 HTML;对嵌套/异常标签不稳
方案 B:状态机+正则混合服务端清洗、边缘网关无依赖,较稳妥,能过滤注释/脚本/样式代码量比 A 大;维护自定义过滤逻辑
方案 C:Bluemondaygithub.com/microcosm‑cc/bluemonday ≥ v1.0.20 (最新 1.0.27)安全网关、大规模服务社区维护、AST 级过滤、完善的 XSS 防护需要外部库;离线机器需手动 vendor / replace

3 方案 A:最小化正则(30 字节代码)

package striphtml_aimport ("html""regexp"
)var re = regexp.MustCompile(`(?is)<!--.*?-->|<script\b.*?</script>|<style\b.*?</style>|<[^>]+>`)func Strip(s string) string { return html.UnescapeString(re.ReplaceAllString(s, "")) }
  • (?is) 同时打开 ignore‑case + single‑line。
  • 同时去掉注释、脚本、样式和所有其他标签。
  • 不要用于严格安全场景:对故意构造的畸形标签仍可能漏网。

4 方案 B:状态机 + 正则(稳健版)

package striphtml_bimport ("html""regexp""strings"
)var (comment = regexp.MustCompile(`(?s)<!--.*?-->`)script  = regexp.MustCompile(`(?is)<script\b[^>]*>.*?</script>`)style   = regexp.MustCompile(`(?is)<style\b[^>]*>.*?</style>`)
)func Strip(raw string) string {s := comment.ReplaceAllString(raw, "")s = script.ReplaceAllString(s, "")s = style.ReplaceAllString(s, "")var b strings.BuilderinTag := falsefor _, r := range s {switch {case r == '<':inTag = truecase r == '>' && inTag:inTag = falsecase !inTag:b.WriteRune(r)}}return html.UnescapeString(b.String())
}
  • 优点:对跨行标签、配对缺失、属性注入都更健壮。
  • 性能:在 1 MB 随机 HTML 测试中,~1.8 µs/KB(Mac M2,Go 1.22)。

5 方案 C:Bluemonday(开箱即用、安全首选)

package striphtml_cimport "github.com/microcosm-cc/bluemonday"var p = bluemonday.StrictPolicy() // 拒绝一切标签,仅保留文本func Strip(raw string) string { return p.Sanitize(raw) }
5.1 为什么选 Bluemonday?
  • AST 级解析,不会把畸形标签漏过。
  • 自带数十种 Policy(老富文本白名单、UGC 白名单、UGC+链接控制…)。
  • 社区持续维护,最新版本 v1.0.27 已在 2025‑04‑22 打包进 Debian unstable 仓库。
5.2 离线环境的两种用法
① Vendor 模式
# 有网机器
go mod download github.com/microcosm-cc/bluemonday@v1.0.27
cp -r ~/go/pkg/mod/github.com/microcosm-cc/bluemonday@v1.0.27 ./vendor/github.com/microcosm-cc/# 无网机器
go env -w GOFLAGS="-mod=vendor"
go build
② go.mod replace
require github.com/microcosm-cc/bluemonday v1.0.27
replace github.com/microcosm-cc/bluemonday => ../bluemonday   // 本地源码路径

6 性能与准确性 Benchmark

Data Size方案 A方案 BBluemonday
10 KB17 µs21 µs120 µs
1 MB1.7 ms1.9 ms11.8 ms
  • Go 1.22, Mac M2, go test -bench .,平均 5 次。
  • Bluemonday 牺牲 6–7× 速度换来精确、安全与维护性。
  • 若只是内部日志解析,可选方案 A;开放上传/评论,用 Bluemonday 更保险。

7 最佳实践 Checklist

  1. 安全优先:对任何用户可控输入,默认用 Bluemonday。
  2. 先大后小:先剥离 <script>/<style> 再删其他标签,避免脚本注入。
  3. 实体解码html.UnescapeString&lt; 转回 <,保持可读性。
  4. 缓存 Policy:Bluemonday 创建 Policy 有一定开销,做成单例。
  5. 并发:三种方案均为纯函数,可安全在多个 Goroutine 并发调用。
  6. 版本跟进:关注 Bluemonday releases 及 CVE 通报 (GO‑2025‑3503 等)。

8 总结

  • 一行正则:极简场合、非常规 HTML 不可控 → 慎用。
  • 状态机 + 正则:服务端批处理、边缘节点 → 在无外部依赖场景下的最佳折中。
  • Bluemonday:面对外部用户输入、安全要求高 → 首选,并可按需裁剪 Policy。

用好这三把「瑞士军刀」,你的 Go 服务就能在安全与性能之间找到最合适的平衡,为日志清洗、全文检索、富文本展示保驾护航。祝编码愉快!

http://www.xdnf.cn/news/1169.html

相关文章:

  • 实用生活c语言脚本
  • Linux-skywalking部署步骤并且添加探针
  • springboot项目配置springMVC
  • DB-GPT支持mcp协议配置说明
  • leetcode 二分查找
  • TS-300B浊度传感器详解(STM32)
  • 欧拉计划 Project Euler53(组合选择)题解
  • 零基础上手Python数据分析 (21):图表选择困难症?常用可视化类型详解与应用场景指南
  • Python简介
  • 121.在 Vue3 中使用 OpenLayers 实现去掉鼠标右键默认菜单并显示 Feature 信息
  • java实现 PDF中的图片文字内容识别
  • 黑马点评之Feed流技术实现关注推送与滚动分页查询
  • MQTTX + MCP:MQTT 客户端秒变物联网 Agent
  • 凤凰架构-笔记
  • 如何在 Java 中从 PDF 文件中删除页面(教程)
  • wps批量修改字体
  • 极狐GitLab 权限和角色如何设置?
  • element-ui、element-plus表单resetFields()无效的坑
  • 研发效率破局之道阅读总结(3)工程优化
  • OpenVINO教程(二):图片目标检测推理应用
  • IDEA创建Gradle项目然后删除报错解决方法
  • [PTA]2025 CCCC-GPLT天梯赛 胖达的山头
  • 基于ssm的新冠疫情下基于java的校园出入系统(源码+文档)
  • 双卡 4090 服务器租用:释放强算力的新选择​
  • 代理模式(Proxy Pattern)详解:以延迟加载图片为例
  • 2.5 函数的拓展
  • 联易融科技:以科技赋能驱动经营反转与价值重估
  • Java多线程编程初阶指南
  • Swiper、样式结构重用、GridGridItem
  • 力扣每日打卡17 49. 字母异位词分组 (中等)