深入了解现代网络浏览器(第 2 部分)

前言

本文是进击的大葱Mario Kosaka写的inside look at modern web browser系列文章的翻译。这里的翻译不是指直译,而是结合个人的理解将作者想表达的意思表达出来,而且会尽量补充一些相关的内容来帮助大家更好地理解。

导航的时候都发生了什么

这是 4 部分博客系列的第 2 部分,该系列探究 Chrome 的内部工作原理。在上一篇文章中,我们探讨了浏览器高层次的架构设计以及多进程架构的带来的好处。同时我们还讨论了服务化和网站隔离这些和浏览器多进程架构息息相关的技术。接下来我们要开始深入了解这些进程和线程是如何呈现我们的网站页面的了。

让我们看一个简单的网页浏览例子:你在浏览器地址栏里面输入一个URL然后按下回车键,浏览器接着会从互联网上获取相关的数据并把网页展示出来。在这篇文章中,我们将会重点关注这个简单场景中网站数据请求以及浏览器在呈现网页之前做的准备工作 - 也就是导航(navigation)的过程。

一切都从浏览器进程开始

我们在第 1 部分:CPU、GPU、内存和多进程架构中提到,浏览器tab外面发生的一切都是由浏览器进程(browser process)控制的。浏览器进程有很多负责不同工作的线程(worker thread),其中包括绘制浏览器顶部按钮和导航栏输入框等组件的UI线程(UI thread)、管理网络请求的网络线程(network thread)、以及控制文件读写的存储线程(storage thread)等。当你在导航栏里面输入一个URL的时候,其实就是UI线程在处理你的输入。

深入了解现代网络浏览器(第 2 部分)_第1张图片

图 1:浏览器的用户界面在顶部,浏览器进程的示意图在底部,里面有UI、网络和存储线程

一次简单的导航

第 1 步:处理输入

当用户开始在地址栏中输入内容时,UI 线程询问的第一件事是“您输入的字符串是搜索的关键词(search query)还是一个URL地址?”。因为对于Chrome来说,地址栏的输入既可能是一个可以直接请求的URL,还可能是用户想在搜索引擎(例如Google)里面搜索的关键词信息,所以 UI 线程需要解析并决定是将用户输入发送到搜索引擎还是直接请求你输入的站点资源。

深入了解现代网络浏览器(第 2 部分)_第2张图片
图 1:UI线程在询问输入的字符串是搜索关键词还是一个URL

第 2 步:开始导航

当用户按下回车键的时候,UI线程会叫网络线程(network thread)初始化一个网络请求来获取站点的内容。这时候tab上会展示一个提示资源正在加载中的旋转圈圈,而且网络线程会进行一系列诸如DNS寻址以及为请求建立TLS连接的操作。

深入了解现代网络浏览器(第 2 部分)_第3张图片
图 2:UI线程告诉网络线程跳转到mysite.com

这时如果网络线程收到服务器的HTTP 301重定向响应,它就会告知UI线程进行重定向然后它会再次发起一个新的网络请求。

第 3 步:读取响应

网络线程在收到HTTP响应的主体(payload)流(stream)时,在必要的情况下它会先检查一下流的前几个字节以确定响应主体的具体媒体类型(MIME Type)。响应主体的媒体类型一般可以通过HTTP头部的Content-Type来确定,不过Content-Type有时候会缺失或者是错误的,这种情况下浏览器就要进行MIME类型嗅探来确定响应类型了。MIME类型嗅探并不是一件容易的事情,你可以从Chrome的源代码的注释来了解不同浏览器是如何根据不同的Content-Type来判断出响应主体是属于哪个媒体类型的。

在缺失 MIME 类型或客户端认为文件设置了错误的 MIME 类型时,浏览器可能会通过查看资源来进行 MIME 嗅探。每一个浏览器在不同的情况下会执行不同的操作。因为这个操作会有一些安全问题,有的 MIME 类型表示可执行内容而有些是不可执行内容。浏览器可以通过请求头 Content-Type 来设置 X-Content-Type-Options 以阻止 MIME 嗅探。

深入了解现代网络浏览器(第 2 部分)_第4张图片
图 3:响应的头部有Content-Type信息,而响应的主体有真实的数据

如果响应的主体是一个HTML文件,浏览器会将获取的响应数据交给渲染进程(renderer process)来进行下一步的工作。如果拿到的响应数据是一个压缩文件(zip file)或者其他类型的文件,响应数据就会交给下载管理器(download manager)来处理。

深入了解现代网络浏览器(第 2 部分)_第5张图片
图 4:网络线程在询问响应的数据是不是来自安全源的HTML文件

网络线程在把内容交给渲染进程之前还会对内容做SafeBrowsing检查。如果请求的域名或者响应的内容和某个已知的病毒网站相匹配,网络线程会给用户展示一个警告的页面。除此之外,网络线程还会做CORBCross Origin Read Blocking)检查来确定哪些敏感的跨站数据不会被发送至渲染进程。

Cross-Origin Read Blocking(下称CORB)不是一个HTTP首部,而是站点隔离机制的一部分[6]。如上文所说,站点隔离可以让不同站点运行在不同进程中,但这样还不够,因为恶意网站仍然可以合法地请求跨源资源。例如,一个恶意网站可以使用一个img元素来请求含有敏感信息(如银行余额)的JSON文件:

这个JSON文件会出现在该恶意站点的渲染器进程的内存中,渲染器发现这不是一个有效的图片格式,于是不渲染这张图片。在类似Spectre漏洞的帮助下,攻击者可以设法访问这部分内存以获取敏感信息。

CORB正是用于阻止这样的访问。如果一个响应被CORB阻止,这个响应甚至不会到达恶意站点所在的进程中,这比之前[7]所讲的不透明响应(脚本不能访问,但可出现在渲染器进程中)更严格[8]

CORB不会检视以下两类请求:

  • 导航请求或各种嵌入请求,例如跨源的、``等。这些嵌入元素本身就有一个独立的安全上下文,在站点隔离的帮助下,其数据与恶意文档的数据分别存于不同进程中,已经足够安全
  • 下载请求,这类请求的响应数据直接储存至硬盘,不会经过跨源文档的上下文,不需要CORB保护

CORB会检视其余的请求,包括:

  • XHRfetch()
  • pingnavigator.sendBeacon()
  • 以下资源的请求:
    • 图像请求,如元素,网站图标/favicon.icoSVG中的CSS中的background-image等等
    • 脚本请求,如

你可能感兴趣的:(深入了解现代网络浏览器(第 2 部分))