安全地在现代 Web 应用程序中托管用户数据

David Dworken
David Dworken

许多 Web 应用程序需要显示用户控制的内容。这可以像提供用户上传的图像(例如,个人资料照片)一样简单,也可以像渲染用户控制的 HTML(例如,Web 开发教程)一样复杂。安全地执行此操作一直很困难,因此我们致力于寻找可以应用于大多数类型的 Web 应用程序的简单但安全的解决方案。

用于隔离不受信任内容的经典解决方案

安全地提供用户控制内容的经典解决方案是使用所谓的沙盒域。基本思想是,如果您的应用程序的主域名是 example.com,您可以将所有不受信任的内容放在 exampleusercontent.com 上。由于这两个域是跨站点,因此 exampleusercontent.com 上的任何恶意内容都不会影响 example.com
这种方法可以用于安全地提供各种不受信任的内容,包括图像、下载和 HTML。虽然对于图像或下载来说,使用这种方法似乎没有必要,但这样做有助于避免来自内容嗅探的风险,尤其是在旧版浏览器中。
沙盒域在整个行业中得到广泛使用,并且长期以来运行良好。但是,它们有两个主要缺点

  • 应用程序通常需要将内容访问限制为单个用户,这需要实施身份验证和授权。由于沙盒域有意不与主应用程序域共享 Cookie,因此这非常难以安全地实现。为了支持身份验证,站点要么必须依赖能力 URL,要么必须为沙盒域设置单独的身份验证 Cookie。第二种方法在现代 Web 中尤其成问题,因为许多浏览器默认限制跨站点 Cookie。
  • 虽然用户内容与主站点隔离,但它并未与其他用户内容隔离。这会产生恶意用户内容攻击沙盒域上的其他数据(例如,通过读取同源数据)的风险。

还值得注意的是,沙盒域有助于减轻网络钓鱼风险,因为资源被清晰地划分为隔离的域。

用于提供用户内容的现代解决方案

随着时间的推移,Web 不断发展,现在有更简单、更安全的方式来提供不受信任的内容。这里有很多不同的方法,因此我们将概述 Google 目前广泛使用的两种解决方案。

方法 1:提供非活动用户内容

如果站点只需要提供非活动用户内容(即不是 HTML 或 JavaScript 的内容,例如图像和下载),那么现在可以安全地完成此操作,而无需隔离的沙盒域。这里有两个关键步骤

  • 始终将 Content-Type 标头设置为所有浏览器都支持的众所周知的MIME 类型,并保证不包含活动内容(如有疑问,application/octet-stream 是一个安全的选择)。
  • 此外,始终设置以下响应标头以确保浏览器完全隔离响应。
响应标头 目的

X-Content-Type-Options: nosniff

X-Content-Type-Options: nosniff

Content-Disposition: attachment; filename="download"

防止内容嗅探

Content-Security-Policy: sandbox

Content-Disposition: attachment

Content-Security-Policy: default-src ‘none'

触发下载而不是渲染

Cross-Origin-Resource-Policy: same-site

Content-Security-Policy: sandbox

将内容沙盒化,就像它是在单独的域上提供的一样

Content-Security-Policy: default-src 'none'

禁用 JavaScript 执行(以及任何子资源的包含)

  • X-Frame-Options: DENY
  • 防止页面被跨站点包含
  • 这些标头的组合确保响应只能作为子资源由您的应用程序加载,或作为文件由用户下载。此外,这些标头通过 CSP sandbox 标头和 default-src 限制提供了针对浏览器错误的多种保护层。总的来说,上面概述的设置提供了高度的信心,即以这种方式提供的响应不会导致注入或隔离漏洞。
    • 纵深防御
    • 虽然上述解决方案通常足以防御 XSS,但您可以应用许多额外的强化措施来提供额外的安全层

设置 X-Content-Security-Policy: sandbox 标头以兼容 IE11。

设置 Content-Security-Policy: frame-ancestors 'none' 标头以阻止端点被嵌入。
通过以下方式在隔离的子域上沙盒化用户内容
在隔离的子域上提供用户内容(例如,Google 使用诸如 product.usercontent.google.com 之类的域)。

  • 设置 Cross-Origin-Opener-Policy: same-originCross-Origin-Embedder-Policy: require-corp 以启用跨域隔离
  • 方法 2:提供活动用户内容
  • 安全地提供活动内容(例如,HTML 或 SVG 图像)也可以在没有经典沙盒域方法的弱点的情况下完成。
  • 最简单的选择是利用 Content-Security-Policy: sandbox 标头来告诉浏览器隔离响应。虽然并非所有 Web 浏览器当前都为沙盒文档实施进程隔离,但对浏览器进程模型的持续改进可能会改善沙盒内容与嵌入应用程序的分离。如果 SpectreJS渲染器泄露 攻击不在您的威胁模型之外,那么使用 CSP sandbox 很可能是一个充分的解决方案。

在 Google,我们开发了一种解决方案,可以通过现代化沙盒域的概念来完全隔离不受信任的活动内容。核心思想是

创建一个新的沙盒域,该域已添加到公共后缀列表。例如,通过将 exampleusercontent.com 添加到 PSL,您可以确保 foo.exampleusercontent.combar.exampleusercontent.com 是跨站点的,因此彼此完全隔离。

*.exampleusercontent.com/shim 匹配的 URL 都路由到一个静态 shim 文件。此 shim 文件包含一个简短的 HTML 和 JavaScript 代码片段,该代码片段侦听 message 事件处理程序并呈现它接收到的任何内容。