html-in-canvas 安全与隐私:哪些敏感信息不能画进Canvas?读回允许渲染(read-back-allowed)完整解读
【免费下载链接】html-in-canvas项目地址: https://gitcode.com/gh_mirrors/ht/html-in-canvas
html-in-canvas 是 Chromium 社区的一个开放提案,让 2D/3D<canvas>直接绘制带样式的 HTML 内容(核心 API 为drawElementImage)。本文面向新手,完整解读它的安全与隐私设计:哪些敏感信息绝不能画进 Canvas,以及 read-back-allowed(读回允许渲染)如何守住像素读回这道安全底线。
为什么"画进Canvas"是个安全敏感操作?
传统上,<canvas>里的像素一旦生成,网页脚本就能通过getImageData()等方法逐像素读回——而 WebGL/WebGPU 的像素读回更是"随时可用"。
html-in-canvas 让 DOM 内容变成 Canvas 像素,等于给脚本开了一条"像素级观测"通道。攻击者可能借此探测两条路:
- 像素读回:把画进 Canvas 的内容读回来逐像素分析;
- 时机侧信道:观察
paint事件是否触发、何时触发,也能推断出画面上发生了什么。
所以设计的第一条铁律是:任何绘制元素快照的 API 和paint事件,绝不能泄露网页代码原本看不到的安全/隐私敏感信息。这个设计就叫read-back-allowed rendering(读回允许渲染)——既然读回总有可能发生,那就保证"画进去的东西不含秘密",读回自然无害。🔒
来源:README.md 的 "Read-back-allowed rendering" 一节。
敏感信息黑名单:这些内容不能画进 Canvas
| # | 敏感信息 | 风险原因 |
|---|---|---|
| 1 | 跨源嵌入内容(<iframe>、<img>等) | 把其他站点的私有数据变成可读像素 |
| 2 | <url>跨源引用(background-image、clip-path) | 同上 |
| 3 | 被跨源数据"污染"的<canvas> | 经典 tainted canvas 场景 |
| 4 | SVG 跨源引用(<use>、<pattern>、<feImage>) | 同上 |
| 5 | 系统颜色、主题、偏好设置 | 可用于设备/系统指纹识别 |
| 6 | 拼写与语法检查标记 | 暴露用户正在书写的内容 |
| 7 | 已访问链接信息(visited) | 暴露浏览历史 |
| 8 | 表单自动填充的待填入内容 | 涉及姓名、卡号等个人数据 |
| 9 | 字幕偏好、IME 候选窗与特殊排版 | 暴露个性化设置与输入行为 |
⚠️ 还有一个容易被忽略的细节:子像素文字抗锯齿同样会被排除,因为它也可被用于指纹识别。
注意一个"部分放行":同源的<iframe>会正常绘制,但其中嵌套的跨源内容不会。
允许清单:这些信息"不算敏感"
有些信息虽然新出现在画布里,但设计文档明确判定它们不敏感——判断标准只有一条:作者代码本就能观察到的信息,才允许出现在画布上。
- 🔍 页面内搜索(find-in-page)与 text-fragment 标记
- 滚动条与表单控件的外观(浏览器中早已可被检测)
- 光标闪烁频率(caret blink rate)
forced-colors(JS 本就能通过媒体查询读取)
侧信道也被堵住:不止像素,还有"刷新时机"
很多 API 只防"画出来",但 html-in-canvas 把invalidation(失效/重绘)通道也纳入了防线:paint事件的触发时机本身就是信息源——比如"某个敏感内容变了"就会多触发一次paint。设计上对敏感信息的剔除是渲染和失效判定同时生效的:不画它,也不会因为它的变化而多触发paint。
官方安全与隐私问卷(security-privacy-questionnaire.md)对关键问题的回答非常直接:
- 不暴露新的安全信息,并尽量把新增隐私信息压到最低;
- 渲染出的像素不允许出现 PII,跨源信息、已访问链接、拼写检查、自动填充预览一律不绘制;
- 不引入跨会话持久化状态、不访问传感器、不新增脚本执行机制,隐私模式下行为无差异。
新手体验:如何在浏览器里试跑
- 使用 Chrome Canary,打开
chrome://flags/#canvas-draw-element启用该特性; - 参考 README.md 的最小示例,核心结构只有两行属性:
<canvas id="canvas" layoutsubtree> <form drawable id="form_element"> <input id="name"> </form> </canvas>在paint事件里调用ctx.drawElementImage(form_element, 100, 0),表单就会被绘制进 Canvas——而上面黑名单里的内容,绘制时会自动被"隐形处理",无需你手动遮罩。
更多可运行的演示(均为仓库内示例):
- 旋转复杂文本:Examples/complex-text.html
- 多行标签饼图:Examples/pie-chart.html
- 3D 立方体贴 HTML:Examples/webGL.html
- 嵌套 drawable 元素:Examples/nested-sparkles.html
- WebGPU 果冻滑块:Examples/webgpu-jelly-slider/
小结:三句话记住这套安全设计
- 画进去的,只限脚本本来就看得见的信息——read-back-allowed 的核心原则;
- 敏感信息在"渲染"和"失效触发"两个通道同时剔除,堵住像素读回与侧信道两条路;
- 用最少的信息换最大的功能:光标、焦点、滚动条等交互所需信息放行,系统偏好、浏览历史、跨源数据一律拦下。
对开发者而言,这套规则意味着你不用自己操心"哪些内容该遮罩",画布天生就是防泄漏的——这正是 html-in-canvas 最值得借鉴的安全设计。
【免费下载链接】html-in-canvas项目地址: https://gitcode.com/gh_mirrors/ht/html-in-canvas
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考