许多 Web 应用都需要显示由用户控制的内容。这可以是简单地提供用户上传的图片(例如个人资料照片),也可以是复杂地呈现用户控制的 HTML(例如 Web 开发教程)。这一直以来都是一项难以安全完成的任务,因此我们一直在努力寻找可应用于大多数类型的 Web 应用的简单而安全的解决方案。
用于隔离不可信内容的传统解决方案
若要安全地分发用户控制的内容,传统的解决方案是使用所谓的沙盒网域。基本思路是,如果应用的主网域是 example.com
,您可以在 exampleusercontent.com
上提供所有不可信内容。由于这两个网域是跨网站的,因此 exampleusercontent.com
上的任何恶意内容都不会影响 example.com
。
这种方法可用于安全地传送所有类型的不受信任内容,包括图片、下载内容和 HTML。虽然似乎没有必要对图片或下载内容使用此方法,但这样做有助于避免内容嗅探风险,尤其是在旧版浏览器中。
沙盒网域在业界广泛使用,并且长期以来运行良好。但这类广告有两个主要缺点:
- 应用通常需要限制单个用户对内容的访问权限,这需要实现身份验证和授权。由于沙盒网域有意不与主应用网域共享 Cookie,因此很难安全地执行此操作。如需支持身份验证,网站必须依赖capability 网址,或者必须为沙盒网域设置单独的身份验证 Cookie。第二种方法在现代网络中尤其成问题,因为许多浏览器默认会限制跨网站 Cookie。
- 虽然用户内容与主网站是隔离的,但与其他用户内容之间并非隔离。这会导致恶意用户内容攻击沙盒网域上的其他数据(例如,通过读取同源数据)。
另请注意,由于资源会明确划分到隔离的网域,沙盒网域有助于降低钓鱼式攻击风险。
用于分发用户内容的现代解决方案
随着时间的推移,网络不断发展,现在有更简单、更安全的方式来投放不可信内容。这里有许多不同的方法,因此我们将简要介绍 Google 目前广泛使用的两种解决方案。
方法 1:投放不活跃用户的内容
如果网站只需提供非活跃用户内容(即非 HTML 或 JavaScript 的内容,例如图片和下载内容),现在无需使用隔离的沙盒网域即可安全地执行此操作。有两个关键步骤:
- 始终将
Content-Type
标头设置为所有浏览器都支持且保证不包含活动内容的知名 MIME 类型(如有疑问,application/octet-stream
是一个安全的选择)。 - 此外,请始终设置以下响应标头,以确保浏览器完全隔离响应。
响应标头 | Purpose |
---|---|
X-Content-Type-Options: nosniff |
防止内容嗅探 |
Content-Disposition: attachment; filename="download" |
触发下载,而不是渲染 |
Content-Security-Policy: sandbox |
将内容沙盒化,就像是在单独的网域中提供内容一样 |
Content-Security-Policy: default-src ‘none' |
停用 JavaScript 执行(以及包含任何子资源) |
Cross-Origin-Resource-Policy: same-site |
阻止将网页包含在跨网站中 |
这种标头组合可确保响应只能由应用作为子资源加载,或由用户作为文件下载。此外,这些标头通过 CSP 沙盒标头和 default-src
限制提供了多层保护,可防范浏览器 bug。总体而言,上述设置可让您高度确信,以这种方式提供的响应不会导致注入或隔离漏洞。
深度防御
虽然上述解决方案通常足以防范 XSS 攻击,但您还可以采取一些额外的强化措施来提供额外的安全层:
- 设置
X-Content-Security-Policy: sandbox
标头以与 IE11 兼容。 - 设置
Content-Security-Policy: frame-ancestors 'none'
标头以阻止嵌入端点。 - 通过以下方式在隔离的子网域中沙盒化用户内容:
- 在隔离的子网域上提供用户内容(例如,Google 使用
product.usercontent.google.com
等网域)。 - 设置
Cross-Origin-Opener-Policy: same-origin
和Cross-Origin-Embedder-Policy: require-corp
以启用跨源隔离。
- 在隔离的子网域上提供用户内容(例如,Google 使用
方法 2:投放活跃用户内容
您还可以安全地分发活动内容(例如 HTML 或 SVG 图片),而不会出现传统沙盒网域方法的缺点。
最简单的方法是利用 Content-Security-Policy: sandbox
标头告知浏览器隔离响应。虽然目前并非所有网络浏览器都针对沙盒文档实现了进程隔离,但随着浏览器进程模型的不断优化,沙盒化内容与嵌入应用之间的隔离可能会得到改善。如果 SpectreJS 和呈现程序遭到入侵攻击不在您的威胁模型范围内,那么使用 CSP 沙盒可能就足以解决问题。
Google 开发了一款解决方案,该解决方案通过对沙盒网域概念进行现代化改造,可完全隔离不可信的活跃内容。其核心理念是:
- 创建一个要添加到公共后缀列表的新沙盒网域。例如,通过向 PSL 添加
exampleusercontent.com
,您可以确保foo.exampleusercontent.com
和bar.exampleusercontent.com
是跨网站的,因此彼此完全隔离。 - 与
*.exampleusercontent.com/shim
匹配的网址都会被路由到静态补丁文件。此修补程序文件包含一个简短的 HTML 和 JavaScript 代码段,用于监听message
事件处理脚本并呈现收到的任何内容。 - 如需使用此功能,该产品会为
$RANDOM_VALUE.exampleusercontent.com/shim
创建 iframe 或弹出式窗口,并使用postMessage
将不可信内容发送到 shim 以进行呈现。 - 渲染的内容会转换为 Blob,并在沙盒化 iframe 中进行渲染。
与传统的沙盒网域方法相比,这种方法可确保所有内容都完全隔离在一个唯一的网站上。此外,通过让主要应用处理要呈现的数据的检索,您无需再使用 capability 网址。
总结
这两种解决方案相辅相成,可让您从 googleusercontent.com
等传统沙盒网域迁移到与第三方 Cookie 屏蔽功能兼容的更安全的解决方案。Google 已经将许多产品迁移到了这些解决方案,并计划在明年进行更多迁移。