在 Mozilla,我们希望 Web 能够运行高性能应用程序,以便用户和内容作者可以选择 Web 平台的安全、自主和开放性。对于许多高性能应用程序而言,共享内存多线程是必不可少的低级构建块。因此,在 2016 年将共享内存交付给 JavaScript 和 WebAssembly 是非常令人兴奋的。 这提供了线程之间极其快速的通信。
但是,我们也希望 Web 能够安全地抵御攻击者。保障用户安全至关重要,这就是为什么共享内存和高分辨率计时器在 2018 年初被有效地禁用,以应对 Spectre 攻击。不幸的是,Spectre 攻击在使用高分辨率计时器时会变得更加有效。而此类计时器可以使用共享内存创建。(通过让一个线程在一个紧循环中递增一个共享内存位置,另一个线程可以将其作为纳秒级分辨率计时器进行采样,从而实现这一点。)
回到绘图板
从根本上说,要使 Spectre 攻击奏效,攻击者和受害者需要驻留在同一个进程中。与您计算机上的大多数应用程序一样,浏览器过去使用单个进程。这将允许两个开放的网站(例如 attacker.example 和 victim.example)相互进行 Spectre 攻击数据,以及浏览器可能保存的其他数据,例如书签或历史记录。浏览器早已变得多进程化。随着 Chrome 的网站隔离和 Firefox 的 Project Fission,浏览器将把每个网站隔离到自己的进程中。这得益于 Web 平台的重新改造的同源策略。
不幸的是,将每个网站隔离到自己的进程中,对于以下原因来说还不够
- 同源策略存在一些漏洞,其中两个在设计过程中强烈地影响了我们的思考方式
- attacker.example 可以将任意 victim.example 资源获取到 attacker.example 的进程中,例如通过 <img> 元素。
- 由于 document.domain 的存在,最小隔离边界是网站(大致为网站主机方案和可注册域名),而不是来源(大致为网站方案、主机和端口)。
- 目前,我们不知道是否可以在所有平台上将每个网站隔离到自己的进程中。在移动设备上,这仍然是一项艰巨的任务。虽然这可能不是一个长期的难题,但我们更希望有一个能够尽快在移动设备上恢复共享内存的解决方案。
提炼需求
我们需要解决上述问题才能恢复共享内存和高分辨率计时器。因此,我们一直在努力构建一个满足以下要求的系统
- 它允许网站将自身从攻击者中隔离出来,从而保护自己免受进程内高分辨率计时器攻击。
- 如果网站想使用这些高性能功能,它还需要将自身从受害者中隔离出来。具体来说,这意味着它必须放弃从任何网站获取任意子资源的能力(例如,通过 <img> 元素),因为这些子资源最终会出现在同一个进程中。相反,它只能从同意来源获取跨域资源。
- 它允许浏览器在一个进程中运行整个网站,包括所有框架和弹出窗口。这对于保持 Web 平台在不同设备上的一致性至关重要。
- 它允许浏览器在每个参与来源(即,不是网站)中运行其自己的进程。这是跨设备的理想最终状态,对于设计来说,不应阻止这种情况的发生。
- 该系统保持向后兼容性。我们不能要求数十亿个网站重写其代码。
由于这些要求,该系统必须提供一种选择加入机制。我们不能禁止网站获取跨域子资源,因为这将不向后兼容。不幸的是,限制 document.domain 也不向后兼容。更重要的是,允许网站通过 <iframe> 元素嵌入跨域文档,并让这些跨域资源最终出现在同一个进程中而无需选择加入是不安全的。
跨域隔离
新的标题
我们与 WHATWG 社区的其他人一起,设计了一组标题来满足这些要求。
Cross-Origin-Opener-Policy 标题允许您将自身从攻击者中隔离出来。它还具有一个良好的效果,即攻击者无法访问您的全局对象,即使他们是在弹出窗口中打开您。这可以防止 XS-Leaks 和各种导航攻击。即使您不打算使用共享内存,也要采用此标题!
Cross-Origin-Embedder-Policy 标题,其值为 require-corp,告诉浏览器仅允许此文档从同意网站获取跨域子资源。从技术上讲,它的工作原理是,这些跨域资源需要指定 Cross-Origin-Resource-Policy 标题,其值为 cross-origin,以表示同意。
对文档的影响
如果为顶级文档设置了 Cross-Origin-Opener Policy 和 Cross-Origin-Embedder-Policy 标题,其值分别为 same-origin 和 require-corp,则
- 该文档将被跨域隔离。
- 任何也设置了 Cross-Origin-Embedder-Policy 为 require-corp 的后代文档将被跨域隔离。(未设置会导致网络错误。)
- 这些文档打开的任何弹出窗口,要么是跨域隔离的,要么与这些文档没有直接关系。也就是说,通过 window.opener 或等效项没有直接访问(即,就像它们是用 rel="noopener" 创建的)。
被跨域隔离的文档将能够访问共享内存,无论是在 JavaScript 中还是在 WebAssembly 中。它只能与同一“选项卡”中同源文档和专用工作程序及其弹出窗口共享内存(从技术上讲,同一浏览器上下文组中的同源代理)。它还将能够访问最高分辨率的 performance.now()。显然,它将无法访问功能性的 document.domain。
这些标题确保来源之间相互同意的方式,使浏览器可以自由地将整个网站放入单个进程或将每个来源放入自己的进程,或者介于两者之间。虽然每个来源一个进程是理想的,但这在所有设备上并不总是可行的。因此,将所有被拉入这些一个或多个进程的内容都同意,是一个不错的折衷方案。
安全后备
我们创建了一个安全后备,以便能够处理新颖的跨进程攻击。并采用了一种方法,避免必须完全禁用共享内存以保持 Web 兼容性。
结果是 Firefox 的 JSExecutionManager。这使我们能够调节不同 JavaScript 上下文之间的执行关系。JSExecutionManager 可用于限制后台选项卡的 CPU 和电源使用率。使用 JSExecutionManager,我们创建了一个动态开关(about:config 中的 dom.workers.serialized-sab-access),它可以阻止所有共享内存的 JavaScript 线程同时运行代码,有效地将这些线程执行为 будто на одноядерной машине. 由于创建使用共享内存的高分辨率计时器需要两个线程同时运行,因此此开关有效地阻止了创建高分辨率计时器,而不会破坏网站。
默认情况下,此开关处于关闭状态,但在发生新颖的跨进程攻击时,我们可以快速将其打开。有了这个开关作为后备,即使考虑到未来不可能发生的 worst-case scenario,我们也可以自信地启用跨域隔离网站中的共享内存。
致谢
非常感谢 Bas Schouten 和 Luke Wagner 对本文的贡献。并且,没有特定顺序,还要感谢 Nika Layzell、Tom Tung、Valentin Gosu、Eden Chuang、Jens Manuel Stutte、Luke Wagner、Bas Schouten、Neha Kochar、Andrew Sutherland、Andrew Overholt、蔡欣宜 (Hsin-Yi Tsai)、Perry Jiang、Steve Fink、Mike Conca、Lars Thomas Hansen、Jeff Walden、Junior Hsu、Selena Deckelmann 和 Eric Rescorla 在 Firefox 中完成这项工作的帮助!
关于 Anne van Kesteren
对隐私和安全边界以及 Web 平台架构感兴趣的标准人员 · he/him
5 条评论