桌面版 Chrome 67 提供了一项名为默认启用网站隔离的新功能。这个 这篇文章介绍了网站隔离的意义、它的必要性,以及 Web 开发者为何应该进行这种隔离 请注意这一点
什么是网站隔离?
在互联网上,人们可以观看猫咪视频、管理加密货币钱包等等 -
但您肯定不希望fluffycats.example
能够访问您的珍贵加密货币!幸运的是,
由于 Same-Origin 优势,网站通常无法在浏览器内访问彼此的数据
政策。尽管如此,恶意网站仍有可能试图绕过此政策攻击其他网站,并且
有时,在强制执行同源政策的浏览器代码中会发现安全错误。通过
Chrome 团队会努力尽快修复此类错误。
网站隔离是 Chrome 的一项安全功能,它提供了一道额外的安全防线, 使此类攻击得不到成功它可确保始终将不同网站的网页 不同的进程,每个进程都在沙盒中运行,从而限制相应进程可执行的操作。 还会阻止相应进程接收来自其他网站的特定类型的敏感数据。作为 因此,利用网站隔离功能,恶意网站将更难使用推测性 从其他网站窃取数据的边信道攻击(如 Spectre)。当 Chrome 团队完成 即使攻击者的网页可以破坏某些 如何在自己的流程中
网站隔离功能可有效降低不受信任的网站访问或窃取信息的难度 来自您在其他网站上的账号。它可针对各种类型的 比如 近期的 Meltdown 和 Spectre 旁路攻击。
如需详细了解网站隔离,请参阅 Google 安全博客上的文章。
跨源读取屏蔽
即使所有跨网站网页都放入不同的进程中,网页仍可以合法地请求
一些跨网站子资源,例如图片和 JavaScript。恶意网页可能会使用
<img>
元素,用于加载包含敏感数据(例如您的银行余额)的 JSON 文件:
<img src="https://your-bank.example/balance.json" />
<!-- Note: the attacker refused to add an `alt` attribute, for extra evil points. -->
如果没有网站隔离,JSON 文件的内容会进入渲染程序的内存 此时渲染程序注意到它不是有效的图片格式, 图片。但是,攻击者随后可能会利用 Spectre 这样的漏洞来读取 内存块
除了使用 <img>
之外,攻击者还可以使用 <script>
将敏感数据提交到
内存:
<script src="https://your-bank.example/balance.json"></script>
跨源读取拦截 (CORB) 是一项新的安全功能,旨在阻止
balance.json
不会根据其 MIME 类型进入渲染程序进程内存的内存。
我们来详细了解一下 CORB 的工作原理。网站可以向服务器请求两种类型的资源:
- 数据资源,例如 HTML、XML 或 JSON 文档
- 媒体资源,例如图片、JavaScript、CSS 或字体
网站可以通过如下方式从自己的来源或其他来源接收数据资源:
宽容的 CORS 标头,例如
Access-Control-Allow-Origin: *
。另一方面,媒体资源可以包含在任何
(即使没有宽松的 CORS 标头)。
CORB 会阻止渲染器进程接收跨源数据资源(即 HTML、XML 或 JSON)中:
- 该资源具有
X-Content-Type-Options: nosniff
标头 - CORS 未明确允许访问该资源
如果跨源数据资源未设置 X-Content-Type-Options: nosniff
标头,
CORB 尝试嗅探响应正文,以确定其是 HTML、XML 还是 JSON。这是
因为某些网络服务器配置有误,无法以 text/html
的形式提供图片。
虽然被 CORB 政策屏蔽的数据资源将作为空资源呈现给进程, 请求仍会在后台执行因此,恶意网页很难 将跨网站数据拉取到其进程中以窃取数据。
为了实现最佳安全性并受益于 CORB,我们建议:
- 使用正确的
Content-Type
标头标记回复。(例如,HTML 资源应该为 作为text/html
、具有 JSON MIME 类型和 XML 资源, XML MIME 类型)。 - 使用
X-Content-Type-Options: nosniff
标头停用嗅探功能。如果没有此标头, Chrome 会进行快速内容分析,以确认类型是否正确,但由于 而是允许响应,以免阻塞 JavaScript 文件、 你最好自己坚定地做对的事。
有关详情,请参阅 “面向 Web 开发者的 CORB”文章 或 深入的 CORB 解说。
Web 开发者为何应关注网站隔离?
在大多数情况下,网站隔离是一项幕后的浏览器功能,不能直接 提供给 Web 开发者。例如,不需要学习任何已在网络上公开的新 API。一般来说, 无论运行网站隔离功能,还是不启用网站隔离功能,网页都应该无法区分这两者。
不过,此规则也有一些例外情况。启用网站隔离功能有一些微妙调整 可能会对您的网站造成影响。我们维护着 一系列已知的网站隔离问题 下面我们将详细说明最重要的一些。
全屏布局不再是同步的
使用网站隔离功能时,我们不再保证全页布局是同步的,因为 一个页面现在可能会分散在多个进程中。如果网页认为 布局更改会立即应用到页面上的所有帧。
例如,假设有一个名为 fluffykittens.example
的网站,该网站与
social-widget.example
上托管的社交微件:
<!-- https://fluffykittens.example/ -->
<iframe src="https://social-widget.example/" width="123"></iframe>
<script>
const iframe = document.querySelector('iframe');
iframe.width = 456;
iframe.contentWindow.postMessage(
// The message to send:
'Meow!',
// The target origin:
'https://social-widget.example'
);
</script>
最初,社交微件的 <iframe>
的宽度为 123
像素。之后,“毛茸茸的猫”页面
将宽度更改为 456
像素(触发布局),并向社交微件发送消息,
,其中包含以下代码:
<!-- https://social-widget.example/ -->
<script>
self.onmessage = () => {
console.log(document.documentElement.clientWidth);
};
</script>
每当社交微件通过 postMessage
API 收到消息时,它就会记录
其根 <html>
元素。
系统会记录哪个宽度值?在 Chrome 启用网站隔离功能之前,答案是 456
。访问
document.documentElement.clientWidth
会强制执行布局,之前在 Chrome 之前是同步布局
已启用网站隔离功能。不过,启用网站隔离功能后,跨源社交微件
重新布局现在在一个单独的进程中异步发生。因此,现在的答案也可以是
123
,即旧的 width
值。
如果网页更改了跨源 <iframe>
的大小,然后向其发送 postMessage
,并且
网站隔离功能在收到消息时,接收框架可能还不知道其新大小。更多
一般来说,如果页面认为布局更改会立即传播到所有
帧数。
在此特定示例中,更可靠的解决方案是在父框架中设置 width
,
通过监听 resize
事件来检测 <iframe>
中的这一变化。
卸载处理程序可能会更频繁地超时
当某个框架导航或关闭时,旧文档以及其中嵌入的任何子框架文档
都会运行各自的 unload
处理程序。如果新的导航发生在同一渲染程序进程中(例如,
同源导航时),旧文档及其子框架的 unload
处理程序可以运行
任意长的时间,之后才允许提交新导航。
addEventListener('unload', () => {
doSomethingThatMightTakeALongTime();
});
在这种情况下,所有帧中的 unload
处理程序都非常可靠。
不过,即使没有网站隔离功能,一些主框架导航也是跨进程导航,这会影响
卸载处理程序行为。例如,如果您通过输入old.example
new.example
地址栏中的网址,new.example
导航会在一个新进程中发生。卸载
old.example
及其子帧的处理程序会在后台的 old.example
进程中运行,
如果 new.example
页面未能显示,旧的卸载处理程序会被终止
在特定超时时间内完成。由于卸载处理程序可能无法在超时前完成,
卸载行为的可靠性会降低。
有了网站隔离功能,所有跨网站导航都会成为跨进程操作,
不同的网站不会共享同一进程因此,上述情况适用于
更多用例,并且 <iframe>
中的卸载处理程序通常具有后台和超时行为
。
网站隔离导致的另一个差异是卸载处理程序的新并行排序方式: 如果不使用网站隔离,卸载处理程序会按照严格的自上而下顺序跨框架运行。但对于网站 隔离、卸载处理程序在不同进程之间并行运行。
这些是启用网站隔离功能的根本后果。Chrome 团队正在努力 在可行的情况下,针对常见用例提高卸载处理程序的可靠性。我们还 了解子框架卸载处理程序还无法使用某些功能且 正在努力解决这些问题。
卸载处理程序的一个重要情况是发送会话结束 ping。这通常作为 如下:
addEventListener('pagehide', () => {
const image = new Image();
img.src = '/end-of-session';
});
鉴于此变化,更可靠的一种更好的方法是使用 navigator.sendBeacon
:
addEventListener('pagehide', () => {
navigator.sendBeacon('/end-of-session');
});
如果您需要更好地控制请求,可以使用 Fetch API 的 keepalive
选项:
addEventListener('pagehide', () => {
fetch('/end-of-session', {keepalive: true});
});
总结
网站隔离功能让不受信任的网站更难以访问或窃取您 账号。其中,CORB 会尝试 将敏感数据资源排除在渲染程序进程之外。上述建议可确保 以便充分利用这些新的安全功能
致谢: Alex Moshchuk, Charlie Reis, Jason Miller, 纳斯科·奥斯科夫 Philip Walton, Shubhie Panicker 和 托马斯·施泰纳 ,欢迎阅读本文的草稿版本并提供反馈。