前端错误 Support Bundle:用户授权、隐私预算与脱敏证明
浏览器报错需要上下文,但整页录屏、请求体和控制台很容易带走令牌与个人数据。本文定义客户端先脱敏、按预算采集的 Support Bundle,让支持人员可复现界面故障又不默认复制用户会话。
本文要点
- 主题聚焦:React、TypeScript、DevOps
- 适合人群:独立开发者、全栈工程师、AI 应用开发者
- 核心价值:快速理解背景、实践路径、常见误区和工程建议
“下载诊断信息”若只是把 console.log、HAR、DOM 和 LocalStorage 打成压缩包,支持团队确实获得了现场,也可能同时获得登录 token、聊天正文、表单输入和内部 URL。完全不采集又会让偶发白屏只剩一句“刷新就好了”。React 错误边界负责在渲染失败时降级 UI,Web 性能 RUM负责聚合指标;Support Bundle 是用户针对一次具体故障主动生成、可预览和有期限的诊断制品。
它也不同于编程 Agent 调试复现包:后者冻结仓库、运行时与测试输入供工程 runner 重演,本篇只描述浏览器已经暴露给最终用户的客户端现场,默认不包含源码、工作树或服务端数据。两种制品可以引用同一个匿名 error fingerprint,但不得互相复制原始内容。
先定义 capturePolicy.v1
服务端签发只读的 web.supportCapturePolicy.v1,包含适用 release、允许的 route template、字段 allowlist、逐类数量和字节上限、脱敏器版本、保留期与支持的 bundle schema。浏览器生成 web.frontendSupportBundle.v1,固定 policy digest、应用 release、浏览器能力、错误 fingerprint、相对时间线、允许的网络元数据、已执行脱敏规则计数和用户 consent receipt。完整 URL、请求/响应 body、Cookie、Authorization、LocalStorage、DOM 文本和剪贴板默认禁止。
schema: web.frontendSupportBundle.v1
policyDigest: sha256:5a7...
release: web@sha256:901...
routeTemplate: /orders/:orderId
budget: { bytes: 262144, seconds: 60, network: 100, events: 200 }
redactionReport: { removed: 47, blockedArtifacts: 2 }
客户端状态限定为 COLLECTING -> SANITIZING -> USER_REVIEW -> SEALED -> UPLOADED。页面关闭或预算耗尽进入 DISCARDED;未完成脱敏的 blob 不能持久化。用户确认 SEALED 摘要后,服务端才签发一次性上传授权,绑定用户、租户、policy digest、bundle digest、nonce 和短 expiry;跨租户、换包或重放一律拒绝。策略升级产生新 digest,旧 reader 不认识必填字段时拒绝上传。
上传成功只进入服务端 RECEIVED_QUARANTINED -> SERVER_VALIDATED -> AVAILABLE,支持人员看不到隔离区。验证失败转 REJECTED 并销毁临时块,不能因客户端声称 removed: 47 就放行;客户端 redaction report 只是对账线索。
脱敏发生在用户设备
网络条目只保留 method、route template、状态码、协议、持续时间和经过 allowlist 的响应头;查询串与 fragment 在进入队列前删除。错误堆栈映射到 release 对应的 source map 后只保存函数与应用内位置,source map 本身留在受控服务。用户操作以 click:save-button 这类稳定组件 ID 表示,不保存键入字符。截图、DOM 片段和 session replay 是独立、默认关闭的额外授权,不能藏在“改善产品”总开关里。
W3C Trace Context 能用 traceparent 关联服务端链路,但其标识也可能成为跨系统关联键;只在同一事故域保留,并按支持租户重新封装引用。高基数账号、邮箱和订单号不能直接做普通哈希,否则可被字典反推;确需同包内关联时使用短期、每包独立的 keyed token,密钥到期即销毁。OpenTelemetry 的敏感数据指南强调在 Collector 或应用中最小化、删除和哈希;这里进一步要求浏览器持久化之前已经完成第一道删除。
上传前界面展示字段类别、条目数、总大小、保留期限和被阻断项,用户可以逐类取消。consent receipt 绑定 bundle digest,不能用昨天的同意上传今天的新包。支持人员按工单、租户与时间获得最小权限;下载与导出都有审计。用户撤销后停止新访问并产生删除回执;若制品已经依法导出到另一个系统,产品必须预先说明边界。Prompt 与 Trace 脱敏治理可复用服务端访问和保留控制,但浏览器策略仍独立版本化。
隔离验证器流式读取归档,同时限制压缩字节、解压总量、压缩比、文件数、单文件大小和嵌套深度;拒绝路径穿越、symlink、重复名及尾随数据。它用固定 parser 重新解析每类文件,按服务端 allowlist 重建对象,丢弃未知字段,再执行第二次脱敏和独立 secret scan。只有重建后的摘要、身份绑定、预算和扫描全通过才进入 AVAILABLE;原始归档不能供支持下载。
把泄漏路径做成攻击夹具
测试页故意把秘密放进 URL query、fragment、GraphQL variables、错误 message、跨 chunk console、DOM input、文件名、source-map sourceContent、WebSocket 帧和第三方属性;再注入压缩炸弹、嵌套归档、海量小文件、无效 UTF-8、伪造客户端报告、上传 token 重放和过期 policy。客户端或服务端应删除、阻断或返回 POLICY_EXPIRED、BUDGET_EXCEEDED、UNSAFE_ARTIFACT、UPLOAD_REPLAY,不能回退成原文。
门禁使用至少 10,000 个对抗样本,要求已知秘密检出和阻断率 100%,禁止字段进入 AVAILABLE 为 0,截断后可解析率 100%,bundle 不超过 256 KiB,解压上限与压缩比绕过为 0,一次授权成功上传恰好一次,取消后的网络请求为 0,失败临时块 30 秒内清零。已知事故盲测的正确根因分类至少 90%,不能放宽隐私字段来提高。
上线先在内存执行 sanitizer 并让服务端验证合成包,不开放下载;随后让内部账号和 1% 主动反馈用户使用。若出现一次禁止字段、授权重放、取消后上传或删除超时,立即撤销 policy、关闭入口、隔离全部同代包;客户端回到只显示 error ID。恢复时提升 policy generation,重跑攻击夹具。MCP 审计日志中的最小暴露原则同样适用。
Related