news 2026/9/25 13:20:25

Highlight 会话录制隐私体系解析:highlight-block / highlight-mask / highlight-ignore 与 privacySetting 的完整实践

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Highlight 会话录制隐私体系解析:highlight-block / highlight-mask / highlight-ignore 与 privacySetting 的完整实践
  • 可观测性
  • 后端

【免费下载链接】highlight

highlight.io: The open source, full-stack monitoring platform. Error monitoring, session replay, logging, distributed tracing, and more.

项目地址:https://gitcode.com/gh_mirrors/hi/highlight
点击查看免费下载

本文围绕 Highlight 的浏览器端会话录制隐私控制展开:如何用最少的 CSS 类名实现元素屏蔽(highlight-block)、文本混淆(highlight-mask)与输入忽略(highlight-ignore),以及如何通过H.init()的privacySetting选项切换 strict / default / none 三级隐私策略。读完本文,你可以对照 Highlight SDK 与 rrweb 的源码实现,理解每一处脱敏发生在客户端序列化的哪个环节,并据此为自己的产品配置一套可复现、可验证的隐私保护方案。

隐私控制的两种入口:CSS 类名与 privacySetting

Highlight 录制会话时,所有脱敏都发生在客户端序列化阶段——敏感数据在离开浏览器之前就已经被移除或替换,服务端(Highlight 后端)从未接收过原始数据。官方文档(privacy.md)给出的控制手段可以归纳为两条路径:

  1. 元素级标注:在 HTML 上添加highlight-block、highlight-mask、highlight-ignore三个 CSS 类,分别控制"屏蔽内容"、"混淆文本"和"忽略输入";
  2. 全局策略:在调用H.init()时传入privacySetting(取值为'strict' | 'default' | 'none'),设定整页的脱敏强度。

从源码结构看,SDK 在启动录制时把这两类配置合并传入底层录制器(rrweb):sdk/highlight-run/src/client/index.tsx 中,record()调用显式传入ignoreClass: 'highlight-ignore'、blockClass: 'highlight-block'以及privacySetting、maskAllInputs、maskInputOptions;而highlight-mask则是 rrweb 侧的默认值,见 __generated/rr/rrweb/rr.js 中record()的默认参数maskTextClass = "highlight-mask"。

privacySetting的可选值定义在 sdk/highlight-run/src/client/types/types.ts:

export type PrivacySettingOption = 'strict' | 'default' | 'none'

其官方文档语义(docs-content/sdk/client.md)为:

  • 'strict':屏蔽页面上所有文本和图片,是无需手动标注即可保证不录制任何个人信息的做法;
  • 'default':只屏蔽匹配常见 PII 正则表达式以及常见输入名的文本和输入数据,不屏蔽图片和媒体内容;
  • 'none':按页面显示原样记录所有文本和内容。

privacySetting的默认值在 SDK 中是'default':sdk/highlight-run/src/client/index.tsx 中this.privacySetting = options.privacySetting ?? 'default'。

Masking Elements:用 highlight-block 屏蔽元素内容

最直接的内容清洗方式是给需要忽略的元素加上highlight-blockCSS 类:

<div class="highlight-block">Super secret sauce</div>

Highlight 片段会测量被忽略元素的尺寸,回放时用占位符替换其内容——即用户能看到该区域"有东西"(布局、尺寸不变),但内容不可见。

对应实现分两层:

  • 判定层:rrweb 序列化时用_isBlockedElement检查节点是否携带 blockClass,匹配规则是element.classList.contains(blockClass),见 __generated/rr/rrweb/rr.js;
  • 默认绑定:record()与snapshot()的默认参数均为blockClass = "highlight-block"(rr.js#L14220、rr.js#L1513),因此不需要任何额外配置,只要 HTML 里加了这个类名即可生效。

注意:highlight-block作用于元素及其整个子树,适合整块区域(如账单明细面板、内部工单卡片)级别的屏蔽。

Obfuscating Elements:用 highlight-mask 混淆文本

如果不想完全隐藏区域、只希望把文本"打码"成乱码,可以给元素加highlight-mask类:

<div class="highlight-mask">This is some sensitive data <button>Important Button</button></div>

其效果等同于privacySetting: 'strict'的文本混淆(即前文图片中看到的随机字符串),但只作用于被标记的具体元素。源码中:

  • snapshot()的默认参数maskTextClass = "highlight-mask"(rr.js#L1515);
  • 判定函数needMaskingText对元素节点检查classList.contains(maskTextClass),对文本节点则检查其父元素(rr.js#L775-L805);
  • 命中后文本会被maskTextFn替换,record()的默认maskTextFn = obfuscateText(rr.js#L14231),最终在序列化节点时执行textContent2 = maskTextFn ? maskTextFn(...) : textContent2.replace(/[\S]/g, "*")(rr.js#L971-L973)。

obfuscateText的实现(rr.js#L576-L580)值得注意:它先剔除非 ASCII 字符,再按空格拆词,对每个词用随机数生成等长的随机字符串,因此回放时文本长度和排版基本保持原样,观感更接近"真实但不可读"的内容,而不是简单的星号:

function obfuscateText(text) { text = text.replace(/[^ -~]+/g, ""); text = (text?.split(" ").map((word) => Math.random().toString(20).substring(2, word.length)).join(" ")) || ""; return text; }

Ignoring Input:用 highlight-ignore 忽略输入内容

注意:highlight-ignore只适用于<input>元素。如果想屏蔽其他 HTML 元素的采集,请使用highlight-block。

对敏感输入框(如身份证号、卡号),团队往往希望保留输入框本身的外观与交互轨迹(光标移动、焦点变化),但不记录用户敲入的值。给<input>加上highlight-ignore即可:

<input class="highlight-ignore" name="social security number" />

源码中该机制对应 rrweb 的输入监听逻辑:record()默认ignoreClass = "highlight-ignore"(rr.js#L14222),输入事件处理器在捕获到目标元素后先做短路判断——target.classList.contains(ignoreClass)命中则直接return,连value都不会读取(rr.js#L12164-L12166)。SDK 侧同样显式传入该配置:record({ ignoreClass: 'highlight-ignore', blockClass: 'highlight-block', ... })(index.tsx#L764-L766)。

这与highlight-mask处理输入的区别在于:highlight-ignore是"输入事件不采集",而 mask/privacy 策略是对已序列化值的替换。

Network Request Redaction:网络层脱敏

DOM 之外的另一个数据出口是网络请求。Highlight 开箱即会屏蔽若干已知携带密钥的请求头,并提供多级自定义能力。完整配置见 Recording Network Requests and Responses,核心要点如下:

  • 开启请求头/响应体录制:networkRecording.recordHeadersAndBody: true;
  • 默认脱敏的请求头:Authorization、Cookie、Proxy-Authorization;
  • 追加脱敏请求头:networkRecording.networkHeadersToRedact;
  • URL 黑名单:urlBlocklist(命中后不记录 header 与 body),Highlight 默认不记录https://www.googleapis.com/identitytoolkit与https://securetoken.googleapis.com;
  • 白名单与键级脱敏:networkRecording.headerKeysToRecord/bodyKeysToRecord(白名单)、networkRecording.networkBodyKeysToRedact(键级脱敏),需highlight.run高于4.1.0;
  • 自定义 sanitizer:networkRecording.requestResponseSanitizer接收 Request/Response pair,返回同类型对象即完成改写,返回null则整条请求被丢弃(官方不建议滥用丢弃,以免调试时缺少请求上下文),需highlight.run高于8.1.0。

示例(来自上述文档):

H.init('<YOUR_PROJECT_ID>', { networkRecording: { enabled: true, recordHeadersAndBody: true, requestResponseSanitizer: (pair) => { if (pair.request.url.toLowerCase().indexOf('ignore') !== -1) { // 丢弃整条请求/响应(不会产生网络日志) return null } // 其余请求正常返回 pair return pair }, }, })

Default Privacy Mode:默认隐私模式与 PII 正则

默认情况下(即privacySetting: 'default'),Highlight 会混淆所有输入以及匹配常见个人信息(PII)正则的文本。这为地址、电话号码、社保号等数据提供了基线保护;图片和媒体内容不受影响。代价是可能"误伤":与长数字、联系方式模式吻合的非 PII 文本也可能被混淆。如需关闭,调用H.init()时将privacySetting设为'none'。

注意:default模式仅在 SDK 8.0.0 及以后版本中可用(早期版本仅 strict / none 二选一)。

使用的正则表达式清单

官方文档列出了默认隐私模式使用的正则(源自 rrweb-snapshot 的utils.ts):

Email: '[a-zA-Z0-9.!#$%&'*+=?^_`{|}~-]+@[a-zA-Z0-9-]+(?:.[a-zA-Z0-9-]+)*' SSN: '[0-9]{3}-?[0-9]{2}-?[0-9]{4}' Phone number: '[+]?[(]?[0-9]{3}[)]?[-\s.]?[0-9]{3}[-\s.]?[0-9]{4,6}' Credit card: '[0-9]{4}-?[0-9]{4}-?[0-9]{4}-?[0-9]{4}' Unformatted SSN, phone number, credit card: '[0-9]{9,16}' Address: '[0-9]{1,5}.?[0-9]{0,3}\s[a-zA-Z]{2,30}\s[a-zA-Z]{2,15}' IP address: '(?:[0-9]{1,3}.){3}[0-9]{1,3}'

当前仓库内置的 rrweb 构建中同样可以找到这份正则清单,定义在 __generated/rr/rrweb/rr.js#L584-L605:EMAIL_REGEX、LONG_NUMBER_REGEX(对应[0-9]{9,16})、SSN_REGEX、PHONE_NUMBER_REGEX、CREDIT_CARD_REGEX、ADDRESS_REGEX、IP_REGEX,由DEFAULT_OBFUSCATE_REGEXES数组聚合,命中判定函数为:

function shouldObfuscateTextByDefault(text) { if (!text) return false; return DEFAULT_OBFUSCATE_REGEXES.some((regex) => regex.test(text)); }

(见 rr.js#L606-L609。)

输入框的脱敏规则从何而来

静态文本靠正则,动态输入靠"整类屏蔽"。SDK 通过 sdk/highlight-run/src/client/utils/privacy.ts 中的determineMaskInputOptions把隐私策略翻译成 rrweb 的maskAllInputs/maskInputOptions:

export const determineMaskInputOptions = ( privacyPolicy: PrivacySettingOption, ): [maskAllOptions: boolean, maskOptions?: MaskInputOptions] => { switch (privacyPolicy) { case 'strict': return [true, undefined] // 屏蔽所有输入 case 'default': return [true, undefined] // 同样屏蔽所有输入 case 'none': { return [false, { password: true }] // 仅屏蔽 password 类型 } }

rrweb 侧的兜底逻辑(rr.js#L14278-L14295):maskAllInputs === true时构造包含text、email、tel、number、textarea、select、password等全部类型的屏蔽表;否则取调用方传入的maskInputOptions;再否则默认{ password: true }。这也解释了为什么none模式下密码框依然会被打码——密码内容属于绝对红线。

被判定应屏蔽的输入,其value会被替换为与原文等长的*串(maskInputValue中text = "*".repeat(text.length),rr.js#L342-L361),保持回放时的宽度稳定。官方博客 Revamping Privacy Mode 还提到:默认模式会额外搜索带有常见name/id/autocomplete值的输入框并从输入第一刻就对其进行混淆,以解决"用户正在输入社保号、但正则要凑够位数才命中"的窗口期问题。

同时该文也点明了默认模式的两类已知局限:一是会过度混淆(如用户创建的UserId长数字命中手机号正则),因为算法不区分上下文;二是跨元素拆分的文本可能漏检(如<div>spencer@<b>highlight</b>.io</div>被<b>切断后整体不再命中邮箱正则)。

覆盖混淆:data-hl-record="true"

默认模式下,一些无害但被误混淆的文本(例如用户自设的名称、公司地址输入框)可以用data-hl-record="true"属性放行。注意两点约束:该属性必须写在被录制的 HTML 标签本身上,且其子元素仍可能各自被脱敏。

源码印证:文本节点混淆前先读取父元素的属性(rr.js#L974-L990):

const enableStrictPrivacy = privacySetting === "strict"; const highlightOverwriteRecord = n2.parentElement?.getAttribute("data-hl-record"); const obfuscateDefaultPrivacy = privacySetting === "default" && shouldObfuscateTextByDefault(textContent2); if ((enableStrictPrivacy || obfuscateDefaultPrivacy) && !highlightOverwriteRecord && parentTagName) { // 忽略 HEAD/TITLE/STYLE/SCRIPT 等标签后执行 obfuscateText }

输入事件路径同样如此:initInputObserver中overwriteRecord = target.getAttribute("data-hl-record"),而maskedInputType在overwriteRecord === "true"时直接返回false(rr.js#L12167-L12188、rr.js#L610-L618),即输入值不再打码。因此该属性对 strict 与 default 两种模式都有效,且作用于元素自身而非其子孙——这与highlight-mask的整树混淆形成互补。

Strict Privacy Mode:最严格的全页混淆

如果不想逐元素标注,可调用H.init()时设置privacySetting: 'strict':

H.init('<YOUR_PROJECT_ID>', { privacySetting: 'strict' })

Strict 模式会混淆所有文本和图片。文档给出的效果示例:

  • <h1>Hello World</h1>会被记录为<h1>1f0eqo jw02d</h1>;
  • <img src="https://my-secrets.com/secret.png" />会被记录为<img src="" />。

两点性质需要强调:混淆不可逆(随机文本由客户端生成,原文从未上传);混淆发生在客户端(序列化阶段即替换,见上节obfuscateText与maskTextFn的调用链)。

从源码结构看,strict 的判定集中在两条链路:初始快照中enableStrictPrivacy = privacySetting === "strict"时对全部文本执行obfuscateText(rr.js#L974-L990),后续 DOM 文本变更则在 MutationObserver 的文本变更分支中做同样的判定与替换(rr.js#L11524-L11528),保证回放时后续出现的动态内容同样被混淆。此外,SDK 在初始化会话时会把策略上报给后端,供回放侧渲染使用:initializeSession请求携带enable_strict_privacy: this.privacySetting === 'strict'与privacy_setting: this.privacySetting(index.tsx#L633-L634)。

三级策略对照与配置建议

维度strictdefault(默认)none
页面文本全部混淆(随机化)仅命中 PII 正则的文本混淆原样记录
图片/媒体全部屏蔽(src置空)不屏蔽原样记录
所有输入框全部打码(等长*)全部打码(等长*)仅password类型打码
是否需要手动标注不需要可选(data-hl-record可放行误伤)不需要
可用版本所有版本SDK 8.0.0+所有版本

配置时的决策路径建议:

  1. 合规要求高、不想逐元素标注→strict;配合data-hl-record="true"放行确需查看的少量元素;
  2. 常规生产环境→ 保持default;对误混淆的元素用data-hl-record="true"精确放行,对整块敏感区域叠加highlight-block,对"保留外观但不录值"的输入框用highlight-ignore,对"保留元素但打码文本"的区域用highlight-mask;
  3. 调试/内网环境→none,此时仍需记住password输入与网络层默认脱敏(Authorization/Cookie等)依然生效。

小结

Highlight 的会话录制隐私控制是一套分层设计:CSS 类名(highlight-block/highlight-mask/highlight-ignore)提供元素级、免配置的精确控制,privacySetting(strict / default / none)提供整页级策略,data-hl-record="true"提供白名单式放行,网络层另有请求头/URL/键级脱敏与自定义 sanitizer。所有脱敏均在客户端序列化阶段完成(rrweb 的 snapshot 与 MutationObserver 两条链路),敏感原文不会离开浏览器。相关实现可追溯至 sdk/highlight-run/src/client/index.tsx、sdk/highlight-run/src/client/utils/privacy.ts 与内置录制器 __generated/rr/rrweb/rr.js;官方说明见 Privacy 文档 与 H.init 参考。

  • 可观测性
  • 后端

【免费下载链接】highlight

highlight.io: The open source, full-stack monitoring platform. Error monitoring, session replay, logging, distributed tracing, and more.

项目地址:https://gitcode.com/gh_mirrors/hi/highlight
点击查看免费下载
上一篇:CocoIndex Postgres 数据源实战:把现有 Postgres 表变成可语义检索的 pgvector 向量索引
下一篇:Open edX Discussions 应用深度解析:多供应商论坛配置与课程话题同步机制

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/25 13:18:57

Linux内核设备模型全解析:kobject、sysfs与驱动绑定机制

1. 为什么Linux内核的"设备模型"值得单独写一篇先说个亲身经历。我刚入行做嵌入式驱动开发那会儿&#xff0c;最崩溃的不是看不懂字符设备驱动怎么写&#xff0c;而是每次要理解一段代码&#xff0c;都会碰到一堆绕不开的名词&#xff1a;kobject、kset、ktype、bus、…

作者头像 李华
网站建设 2026/9/25 13:17:17

CPO架构下超低损耗紧凑型SiP偏振补偿器设计与实操

1. 从CPO架构的激光困局说起1.1 为什么CPO离不开外部激光源CPO&#xff0c;也就是共封装光学&#xff08;Co-Packaged Optics&#xff09;&#xff0c;这两年在数据中心和AI算力集群里被讨论得越来越多。它的核心思路很直接&#xff1a;把光引擎和交换ASIC芯片封装在同一个基板…

作者头像 李华
网站建设 2026/9/25 13:12:58

SQL Server人事管理系统课程设计:从建库到触发器与索引优化实战

简介&#xff1a;这份资源是面向高校数据库课程设计场景的完整项目包&#xff0c;主题为基于SQL Server的人事管理系统&#xff0c;适合正在学习数据库原理、需要完成课程设计或想打通Java GUI与数据库连接的中级学习者。包内共197个文件&#xff0c;以116个class编译文件、18个…

作者头像 李华
网站建设 2026/9/25 13:12:00

Delphi 12.3安装NextSuite VCL组件:Full Source含义与编译避坑

简介&#xff1a;面向 Delphi 与 C Builder 开发者的 Bergsoft NextSuite (VCL) v6.40.0 全源码组件包&#xff0c;完整支持 Delphi/C Builder 6 至 12 及 Athens 版本&#xff0c;特别适配 Delphi 12.3 环境&#xff0c;适合需要增强界面控件、数据网格、属性检查器与项目管理…

作者头像 李华
网站建设 2026/9/25 13:11:59

让AI Agent替你查账号:Aliens Eye MCP服务器接入LLM完整指南

让AI Agent替你查账号&#xff1a;Aliens Eye MCP服务器接入LLM完整指南 【免费下载链接】Aliens_eye Hunt down 840 social media accounts using AI 项目地址: https://gitcode.com/gh_mirrors/al/Aliens_eye Aliens Eye 是一款用 AI 驱动的 OSINT 账号嗅探工具&#…

作者头像 李华
网站建设 2026/9/25 13:11:33

上海企业知识库怎么建设?RAG检索质量、权限隔离与更新机制详解

摘要&#xff1a;RAG知识库的价值取决于资料治理、检索命中、权限继承和更新时效。上海企业应先整理知识源&#xff0c;再测试模型回答。 RAG知识库应先完成资料治理&#xff0c;再用真实问题验证检索、引用、权限和更新时效。先看业务情境&#xff1a;这个问题为什么会出现假设…

作者头像 李华