News Hacker|极客洞察

233 11 天前 muffin.ink
⚠️SVG 清理困局:Scratch 漏洞、CSP 与安全子集之争
拿正则洗 SVG,就敢说已经安全了?

🎯 讨论背景

这场讨论围绕 Scratch(一个面向编程教育的网页平台)如何处理用户上传的 SVG(可缩放矢量图形)展开。为了测量图片边界,Scratch 需要把 SVG 先插入 DOM 并调用 `getBBox()`,这让原本应当当作“图片”的文件变成了更接近网页文档的内容。评论里提到,早期版本曾用正则表达式清理 ` `,但 SVG 里还有 CSS、外链资源、`foreignObject`、DTD、namespace tricks 等多种绕过路径,因此单纯 sanitization 很容易漏。大家还讨论了更稳妥的方向:用 CSP(Content Security Policy,内容安全策略)、`iframe sandbox`、`srcdoc`,或者像 SVG Native / tinyVG 这样的安全子集格式,尽量把动态能力从文件格式里剥离出去。

📌 讨论焦点

CSP / sandbox 更靠谱

评论者认为,处理用户 SVG 最可靠的办法不是继续补丁式清理,而是用 CSP 和 sandbox 直接限制能力。有人演示了在 `iframe srcdoc` 里用 ` ` 下发策略的做法,即使没有 HTTP header 也能生效,而且现代浏览器会把它锁定为不可被脚本篡改。大家还补充说,`meta` 只能进一步收紧规则,不能把原本禁止的东西重新放开。对于不可信内容,`Sec-Fetch-` 头部和严格的 `sandbox` 可以作为额外约束,但核心仍然是浏览器层的 CSP。

[来源1] [来源2] [来源3] [来源4] [来源5] [来源6] [来源7]

安全子集 / 新格式提案

另一派主张把 SVG 切成更小的“安全子集”,只保留路径、填充、基础渐变等大多数真实场景需要的静态能力。评论里反复提到 SVG Native、SVG Tiny、SVG Tiny PS、tinyVG,甚至类似 SVG-ES 的设想,目标都是把脚本、外链、动画和复杂解析特性剥离出去。支持者认为这样既能满足浏览器和设计工具的互操作,又能避免把完整 HTML 级别的风险塞进图片格式。质疑点主要是 adoption:如果没有统一标准和工具链,设计师导出的 SVG 还是很难直接迁移。

[来源1] [来源2] [来源3] [来源4] [来源5] [来源6] [来源7] [来源8] [来源9] [来源10] [来源11]

黑名单式 sanitization 太脆弱

不少评论直接批评黑名单式 sanitization,认为 SVG 里可利用的入口太多,删几个标签远远不够。除了 ` `,还要考虑 `image`、`feImage`、`foreignObject`、事件属性、DTD、namespace tricks,以及 CSS 和 presentational attributes 里的外链加载。有人指出,正则清理脚本标签这种做法已经被反复证明不可靠,但现实产品里依然会出现。更激进的观点是,真正的安全边界应当在渲染引擎里实现,而不是靠不断加规则的后处理。

[来源1] [来源2] [来源3] [来源4] [来源5] [来源6] [来源7] [来源8]

Scratch 的实现与修补争议

讨论中最具体的案例是 Scratch 3 的 SVG 处理:它为了测量图形尺寸,需要把用户 SVG 先放进 DOM,再调用 `getBBox()`,因为旧项目里常常存在不准确的 viewBox。评论里提到,Scratch 在 2019 年曾因为 SVG 中的 ` ` 触发 XSS,而当时的修复方式是用正则去删脚本标签。后来又有人指出,这类修补并没有真正解决完整攻击面,甚至围绕责任披露、后续文章的写法也引发了强烈争议。顺带一提,Scratch 现在已是基于标准浏览器的网页应用,桌面端则跑在 Electron 上,这也解释了为什么浏览器语义会直接影响它的安全边界。

[来源1] [来源2] [来源3] [来源4] [来源5] [来源6] [来源7] [来源8]

嵌入方式决定风险与功能

很多评论强调,同一个 SVG 在不同嵌入方式下安全性差异巨大:` ` 通常会禁掉脚本和外部请求,而 ` ` 和内联 ` ` 则会把很多动态能力一并放进来。也有人提到,把 SVG 直接打开成新标签页时,用户其实是在用“文档模式”查看它,单靠图片级别的假设并不安全。与此同时,` ` 方案会牺牲 CSS variables、主题色、部分动画和可交互效果,所以有些产品在安全和表现力之间会非常纠结。Google Slides、邮件阅读器、Cloudflare 的 `svg-hush` 等例子表明,很多平台最终选择的不是“完美支持”,而是保守地限制或转换 SVG。

[来源1] [来源2] [来源3] [来源4] [来源5] [来源6] [来源7] [来源8] [来源9] [来源10] [来源11] [来源12] [来源13] [来源14] [来源15]

📚 术语解释

CSP(Content Security Policy,内容安全策略): 浏览器级安全策略,用来限制脚本、外链资源、iframe 等的加载与执行范围。

srcdoc: `iframe` 的内联 HTML 来源属性,可以直接在属性里嵌入一段文档内容。

getBBox(): SVG 的布局测量 API,用来获取元素边界框,常用于计算内容尺寸。

SVG Native: W3C 提出的 SVG 安全子集规范,去掉脚本、动画和外部引用。

tinyVG: 一种更小、更安全的矢量图格式提案,目标是替代复杂且危险的完整 SVG 能力。

SMIL: SVG 的原生动画机制之一,支持声明式动画。

Sec-Fetch-Dest / Sec-Fetch- 头部: 浏览器请求上下文标头,可用来判断资源是以 document、iframe 还是 image 等方式被加载。