安全恢复共享内存

2020-07-22 01:00:57

在Mozilla,我们希望Web能够运行高性能的应用程序,这样用户和内容作者就可以选择Web平台的安全性、代理性和开放性。许多高性能应用程序的一个基本低级构建块是共享内存多线程。这就是为什么在2016年向JavaScript和WebAssembly交付共享内存是如此令人兴奋的原因。这在线程之间提供了极快的通信。

然而,我们也希望网络不受攻击者的攻击。根据Spectre的说法,确保用户的安全是最重要的,这就是为什么共享内存和高分辨率定时器在2018年初被有效禁用的原因。不幸的是,使用高分辨率定时器可以显著提高频谱攻击的效率。并且这样的定时器可以用共享存储器创建。(这是通过让一个线程在紧密循环中递增共享内存位置来实现的,另一个线程可以将其作为纳秒精度计时器进行采样。)。

从根本上说,要使Spectre攻击起作用,攻击者和受害者需要驻留在同一进程中。与计算机上的大多数应用程序一样,浏览器过去使用单个进程。这将允许两个开放的站点,例如攻击者和受害者。例如,对彼此的数据以及浏览器可能保存的其他数据(如书签或历史记录)进行频谱攻击。浏览器早已成为多进程浏览器。随着Chrome的站点隔离和Firefox的Project裂变,浏览器将把每个站点隔离到它自己的进程中。这要归功于网络平台改进后的同源政策。

遗憾的是,出于以下原因,将每个站点隔离到其自己的进程中仍然是不够的:

同源策略有许多漏洞,其中两个漏洞强烈地启发了我们在设计过程中的想法:attacker.example可以将任意受害者.example资源提取到attacker.example的进程中,例如,通过<;img>;元素。

由于Document.domain的存在,最小隔离边界是站点(大致是网站主机的方案和可注册域),而不是来源(大致是网站的方案、主机和端口)。

在这一点上,我们不知道是否可以跨所有平台将每个站点隔离到其自己的进程中。在移动设备上,这仍然是一项具有挑战性的努力。虽然这可能不是一个长期的问题,但我们更倾向于一种解决方案,允许在不久的将来在移动设备上恢复共享内存。

我们需要解决上述问题以恢复共享内存和高分辨率计时器。因此,我们一直致力于开发一种满足以下要求的系统:

它允许网站将自己与攻击者进程隔离,从而保护自己免受进程内高精度计时器的攻击。

如果一个网站想要使用这些高性能的功能,它还需要处理-将自己与受害者隔离开来。特别是,这意味着它必须放弃从任何站点获取任意子资源的能力(例如,通过<;img>;元素),因为这些资源最终都在同一进程中。相反,它只能从同意的来源获取跨来源的资源。

它允许浏览器在单个进程中运行整个网站,包括所有框架和弹出窗口。这对于保持Web平台跨设备的一致性系统非常重要。

它允许浏览器在其自己的进程中运行每个参与源(即,不是站点)。这是跨设备的理想终端状态,因此设计不要阻止这一点非常重要。

该系统保持向后兼容性。我们不能要求数十亿个网站重写它们的代码。

由于这些要求,系统必须提供选择加入机制。我们不能禁止网站获取跨源子资源,因为这不会向后兼容。遗憾的是,限制Document.domain也不能向后兼容。更重要的是,允许网站通过<;iframe>;元素嵌入跨来源文档,并让这些跨来源资源在没有选择加入的情况下最终出现在同一进程中,这是不安全的。

我们与WHATWG社区中的其他人一起设计了一组满足这些要求的标头。

跨域开放策略标头允许您处理-将自己与攻击者隔离。它还具有理想的效果,即如果攻击者在弹出窗口中打开您的全局对象,则他们无法访问您的全局对象。这可以防止XS泄漏和各种导航攻击。即使您不打算使用共享内存,也要采用此标头!

值为Required-Corp的Cross-Origin-Embedder-Policy标头告诉浏览器仅允许此文档从同意的网站获取跨源子资源。从技术上讲,其工作方式是那些跨域资源需要指定值为CrossSource的Cross-Origin-Resource-Policy标头以表示同意。

如果为具有相同来源和要求公司值的顶层单据分别设置了跨域开户策略和跨域嵌入器策略题头,则:

还将跨域-嵌入器-策略设置为Required-Corp的任何子体文档都将是跨域隔离的。(不设置它会导致网络错误。)。

这些文档打开的任何弹出窗口要么是跨来源隔离的,要么与这些文档没有直接关系。这就是说,不能通过window.opener或等效物直接访问(也就是说,它们就好像是使用rel=#34;noopener&34;创建的一样)。

跨源隔离的文档可以访问JavaScript和WebAssembly中的共享内存。它将只能与同一“选项卡”及其弹出窗口中的同源文档和专用工作者共享内存(从技术上讲,同源代理位于单个浏览上下文组中)。它还可以访问可用的最高分辨率性能。now()。显然,它将无法访问功能文档.domain。

这些标头确保来源之间相互同意的方式使浏览器可以自由地将整个网站放入单个进程中,或将每个来源放入自己的进程中,或者介于两者之间。虽然按来源进程是理想的,但这在所有设备上并不总是可行的。因此,将所有东西都纳入到这些一个或多个过程中,同意是一个像样的中间立场。

我们创建了一个安全后盾,以便能够处理新的跨进程攻击。并且使用了一种避免为了保持web兼容而必须完全禁用共享存储器的方法。

结果是Firefox的JSExecutionManager。这使我们能够控制不同JavaScript上下文的执行。JSExecutionManager可用于通过后台选项卡限制CPU和电源使用。使用JSExecutionManager,我们创建了一个动态开关(about:config中的dom.workers.Serialized-SAB-Access),它可以防止所有共享内存的JavaScript线程并发运行代码,从而有效地执行这些线程,就像在单核计算机上一样。由于使用共享内存创建高分辨率计时器需要两个线程同时运行,因此此开关可在不中断网站的情况下有效阻止创建高分辨率计时器。

默认情况下,此开关处于关闭状态,但在发生新的跨进程攻击的情况下,我们可以快速将其打开。有了这一转换作为后盾,即使考虑到未来不太可能出现的最坏情况,我们也可以自信地在跨来源的孤立网站中启用共享内存。

非常感谢巴斯·舒腾和卢克·瓦格纳为这篇文章所做的贡献。而且,没有特别的顺序,非常感谢Nika Layzell,汤姆·董,Valentin Gosu,Eden Chuang,Jens Manuel Stutte,Luke Wagner,Bas Schouten,Neha Kochar,Andrew Sutherland,Andrew Overholt,蔡欣宜(蔡信义),Perry酱,Steve Fink,Mike Conca,Lars Thomas Hansen,Jeff Walden,Junior Hsu,Selena Deckelmann和Eric Rescorla