为什么需要“跨源隔离”来实现强大的功能

了解为何需要进行跨源隔离才能使用 SharedArrayBufferperformance.measureUserAgentSpecificMemory() 和高分辨率计时器等功能,从而提高精确度。

简介

使用 COOP 和 COEP 使您的网站“跨源隔离”中,我们介绍了如何使用 COOP 和 COEP 采用“跨源隔离”状态。本文是一篇配套文章,介绍了为什么需要进行跨源隔离才能在浏览器上启用强大的功能。

背景

Web 基于同源政策构建而成:这是一项安全功能,可限制文档和脚本与来自其他来源的资源之间的互动方式。此原则限制了网站访问跨源资源的方式。例如,来自 https://a.example 的文档无法访问托管在 https://b.example 的数据。

不过,同源政策在历史上有一些例外情况。任何网站都可以:

  • 嵌入跨源 iframe
  • 包含图片或脚本等跨源资源
  • 使用 DOM 引用打开跨源弹出式窗口

如果可以从头开始设计网络,就不会出现这些例外情况。 遗憾的是,当 Web 社区意识到严格的同源政策的关键优势时,Web 已经依赖于这些例外情况。

我们通过两种方式修补了这种宽松的同源政策带来的安全副作用。一种方法是引入一种名为跨源资源共享 (CORS) 的新协议,该协议旨在确保服务器允许与给定来源共享资源。另一种方法是隐式移除对跨源资源的直接脚本访问权限,同时保持向后兼容性。此类跨源资源称为“不透明”资源。例如,这就是为什么除非对跨源图片应用 CORS,否则通过 CanvasRenderingContext2D 操作跨源图片的像素会失败。

所有这些政策决策都是在浏览上下文组中做出的。

浏览上下文组

在很长一段时间内,CORS 和不透明资源的组合足以确保浏览器安全。有时,我们发现了边缘情况(例如 JSON 漏洞),需要进行修补,但总体而言,不允许直接读取跨源资源的原始字节的原则是成功的。

但随着 Spectre 的出现,这种情况发生了变化,该漏洞可能会导致加载到与您的代码相同的浏览上下文组中的任何数据被读取。通过测量某些操作所花费的时间,攻击者可以猜测 CPU 缓存的内容,进而猜测进程内存的内容。此类时序攻击可以通过平台中存在的低粒度计时器实现,但可以通过显式(如 performance.now())和隐式(如 SharedArrayBuffer)高粒度计时器加快速度。如果 evil.com 嵌入了跨源图片,攻击者可以使用 Spectre 攻击来读取其像素数据,从而使依赖“不透明度”的保护措施失效。

Spectr

理想情况下,所有跨源请求都应由资源所属的服务器明确审查。如果资源所有者服务器未提供审查,则数据永远不会进入恶意行为者的浏览上下文组,因此不会受到网页可能发起的任何 Spectre 攻击。我们称之为“跨域隔离状态”。 这正是 COOP+COEP 的意义所在。

在跨源隔离状态下,请求网站被认为不太危险,这会解锁强大的功能,例如 SharedArrayBufferperformance.measureUserAgentSpecificMemory()高分辨率计时器,这些计时器具有更高的精度,否则可能会被用于类似 Spectre 的攻击。它还会阻止修改 document.domain

跨源嵌入器政策

跨源嵌入者政策 (COEP) 可防止文档加载任何未明确授予该文档权限(使用 CORP 或 CORS)的跨源资源。借助此功能,您可以声明文档无法加载此类资源。

COEP 的运作方式

如需激活此政策,请将以下 HTTP 标头附加到文档中:

Cross-Origin-Embedder-Policy: require-corp

COEP 采用单个值 require-corp。这会强制执行以下政策:文档只能加载来自同一来源的资源,或明确标记为可从其他来源加载的资源。

如需从其他来源加载资源,这些资源需要支持跨源资源共享 (CORS) 或跨源资源政策 (CORP)。

跨源资源共享

如果跨源资源支持跨源资源共享 (CORS),您可以使用 crossorigin 属性将其加载到网页中,而不会被 COEP 阻止。

<img src="https://third-party.example.com/image.jpg" crossorigin>

例如,如果此图片资源是通过 CORS 标头提供的,请使用 crossorigin 属性,以便提取资源的请求将使用 CORS 模式。这还会阻止加载图片,除非图片设置了 CORS 标头。

同样,您可以通过 fetch() 方法提取跨源数据,只要服务器以正确的 HTTP 标头做出响应,就不需要特殊处理。

跨源资源政策

跨源资源政策 (CORP) 最初是作为一种选择性加入的机制引入的,旨在保护您的资源免遭其他来源加载。在 COEP 的上下文中,CORP 可以指定资源所有者关于谁可以加载资源的政策。

Cross-Origin-Resource-Policy 标头可采用以下三个可能的值:

Cross-Origin-Resource-Policy: same-site

标记为 same-site 的资源只能从同一网站加载。

Cross-Origin-Resource-Policy: same-origin

标记为 same-origin 的资源只能从同一来源加载。

Cross-Origin-Resource-Policy: cross-origin

标记为 cross-origin 的资源可由任何网站加载。(此值已添加到 CORP 规范中,同时添加了 COEP。)

跨源打开者政策

借助跨源开放者政策 (COOP),您可以将顶级窗口与其他文档置于不同的浏览上下文组中,从而确保顶级窗口与其他文档隔离,使它们无法直接与顶级窗口互动。例如,如果具有 COOP 的文档打开了一个弹出式窗口,则其 window.opener 属性将为 null。此外,开启者对其的引用中的 .closed 属性将返回 true

COOP

Cross-Origin-Opener-Policy 标头可采用以下三个可能的值:

Cross-Origin-Opener-Policy: same-origin

标记为 same-origin 的文档可以与同样明确标记为 same-origin 的同源文档共享相同的浏览上下文组。

COOP

Cross-Origin-Opener-Policy: same-origin-allow-popups

具有 same-origin-allow-popups 的顶级文档会保留对其任何弹出式窗口的引用,这些弹出式窗口要么未设置 COOP,要么通过将 COOP 设置为 unsafe-none 选择不进行隔离。

COOP

Cross-Origin-Opener-Policy: unsafe-none

unsafe-none 是默认值,允许将文档添加到其打开者的浏览上下文组,除非打开者本身的 COOP 为 same-origin

摘要

如果您想保证能够使用 SharedArrayBufferperformance.measureUserAgentSpecificMemory()高分辨率计时器等功能强大的功能,并获得更高的精度,只需记住您的文档需要同时使用值为 require-corp 的 COEP 和值为 same-origin 的 COOP。如果缺少其中任何一个,浏览器将无法保证足够的隔离,从而无法安全地启用这些强大的功能。您可以检查 self.crossOriginIsolated 是否返回 true,从而确定网页的情况。

如需了解实现此功能的步骤,请参阅使用 COOP 和 COEP 使网站“跨源隔离”

资源