代表性面试主题

产品面试:是否应该采用 HTML Sanitizer API 构建富文本编辑器?

产品困难
Offer.cc 编辑团队发布 更新

题干

你的 SaaS 计划支持用户发布富文本。是否应采用浏览器原生 HTML Sanitizer API?请给出决策框架、渐进式兼容方案和上线指标。

题目与使用场景

SaaS 产品准备支持评论、知识库和模板中的用户富文本。团队希望采用浏览器原生 HTML Sanitizer API,减少自维护过滤规则,但该 API 在部分主流浏览器中仍不可用。请决定是否采用,并说明安全、体验、兼容和运营取舍。

面试官考察什么

  • 是否先定义威胁模型、允许的内容能力和服务端信任边界。
  • 能否区分 setHTML()、自定义 Sanitizer、setHTMLUnsafe() 与 Trusted Types 的职责。
  • 是否把浏览器覆盖、降级实现、内容一致性和迁移成本量化。
  • 能否用分阶段指标验证 XSS 风险、编辑成功率、性能和回滚能力。

作答前的澄清问题

先确认富文本是否需要链接、图片、表格、嵌入、样式和自定义属性;确认内容是否会被服务端渲染、邮件导出、搜索索引或多端复用。再确认支持的浏览器、现有过滤库、合规要求、攻击面和可接受的功能降级。

30 秒回答框架

我会采用“原生 API 优先、服务端持续校验、能力分级降级”的方案,而不是一次性替换现有过滤器。原生 setHTML() 可按规范移除脚本能力标记,但 API 覆盖有限;不支持时使用经过审计的同等策略。先以评论等低复杂场景灰度,指标包括危险载荷拦截、内容保真、编辑成功率、渲染性能和浏览器分布。服务端仍需独立清洗与输出编码,Trusted Types 作为注入汇点的额外约束。

分步骤深入解答

1. 定义用户价值和威胁模型

用户价值是更稳定地发布可格式化内容;主要风险是将不可信 HTML 送入 DOM 或其他渲染汇点。先建立允许元素、属性、链接协议和媒体来源清单,再决定哪些功能值得承担维护成本。

2. 区分原生 API 的能力

Element.setHTML()Document.parseHTML() 使用安全默认清理;自定义配置可以收紧允许列表。setHTMLUnsafe() 适合需要保留某些特殊结构的场景,但必须配合严格配置和审计。规范要求安全方法不能保留脚本能力标记,不能把 API 当作任意 HTML 的通行证。

3. 评估覆盖和降级

MDN 将 HTML Sanitizer API 标为 Limited availability。通过能力检测选择原生路径或服务端/成熟库路径,并让两条路径共享允许列表、测试样例和版本记录。降级时宁可丢弃高风险能力,也不要为了视觉一致放宽策略。

4. 设计跨端内容契约

服务端保存原始输入与规范化后的安全表示,明确哪个表示用于编辑、预览、邮件、搜索和导出。服务端在每个输出边界重新校验,客户端清理只减少 DOM 注入风险,不能替代服务端授权、存储和渲染策略。

5. 设计灰度和指标

先在单一内容类型和少量租户开启,比较原生与降级路径的拦截结果。核心指标包括危险内容拦截率、误删申诉率、编辑提交成功率、首屏和输入延迟、浏览器覆盖、策略版本一致性和安全事件数。

6. 处理 Trusted Types 和运营流程

对高风险注入汇点启用 Trusted Types 报告或强制模式,要求策略函数输出经过验证的类型。建立规则变更审批、恶意样本回归、内容重处理和紧急回滚流程;不要只依赖浏览器更新来改变安全策略。

高质量示范回答

我会先把决策拆成内容能力、威胁模型和运行环境三张表。HTML Sanitizer API 适合在浏览器侧把不可信 HTML 送入 DOM 前做结构化清理,setHTML() 的安全默认值和 WHATWG 规范减少了脚本能力标记被保留的风险,但 MDN 仍标记其覆盖有限。产品方案采用原生 API 优先、成熟库或服务端策略降级;两条路径共享允许元素、属性、协议和测试样例。服务端保存原始内容与安全表示,在页面、邮件、搜索和导出边界分别校验,客户端清理不承担权限或完整 XSS 防护。先灰度评论场景,按危险载荷拦截、内容保真、提交成功率、性能、浏览器分布和安全事件评估。setHTMLUnsafe() 只在确有结构需求时使用,并配合严格配置、Trusted Types 和人工审计。规则升级可回放历史恶意样本,发现回归时立即切回上一版策略。

常见错误

  • 因为是浏览器原生 API 就认为服务端无需清理。
  • 只看功能演示,不测不支持浏览器和降级路径的一致性。
  • 为保留任意嵌入而放宽 setHTMLUnsafe() 配置。
  • 用单一“过滤成功率”替代内容保真、误删和安全事件指标。
  • 把 Trusted Types 当作清理器,或把清理器当作权限控制。

追问及应对

为什么不直接全面切换原生 API?

浏览器覆盖、内容能力和旧数据迁移仍有不确定性。先灰度并保持可回滚的降级路径,能验证真实浏览器和内容分布。

如何处理原生 API 与服务端规则不一致?

共享版本化允许列表和恶意样本,服务端作为最终边界;客户端发现差异时记录策略版本和内容样本,禁止静默放宽规则。

何时值得开启 Trusted Types 强制模式?

当主要注入汇点已盘点、策略函数和第三方组件完成改造,并在报告模式下观察到低误报后,再逐步切换强制模式。

公开来源

同类题目