沙箱环境
沙箱环境听起来很复杂,但其实前端开发者经常接触到:除了浏览器环境以外,JavaScript 还会被运行在 Node. Js 环境中。Node. Js 是基于 Chrome V8 引擎的 JavaScript 运行环境,该环境中不存在 DOM API、window、document 等对象 API 和全局对象,因此也更无操作 DOM 节点一说。
安全沙箱,就是将渲染进程和操作系统隔离的一道墙,由于这道墙,黑客就获取不到渲染进程之外的任何操作权限。
我们知道安全沙箱最小的保护单位是进程,并且能限制进程对操作系统资源的访问和修改,这就意味着如果要让安全沙箱应用在某个进程上,那么这个进程必须没有读写操作系统的功能,比如读写本地文件、发起网络请求、调用 GPU 接口等。

持久存储
具体地讲,如下文件内容的读写都是在浏览器内核中完成的:
- 存储 Cookie 数据的读写。通常浏览器内核会维护一个存放所有 Cookie 的 Cookie 数据
库,然后当渲染进程通过 JavaScript 来读取 Cookie 时,渲染进程会通过 IPC 将读取
Cookie 的信息发送给浏览器内核,浏览器内核读取 Cookie 之后再将内容返回给渲染进
程。 - 一些缓存文件的读写也是由浏览器内核实现的,比如网络文件缓存的读取。
网络访问
同样有了安全沙箱的保护,在渲染进程内部也是不能直接访问网络的,如果要访问网络,则需要通过浏览器内核。不过浏览器内核在处理 URL 请求之前,会检查渲染进程是否有权限请求该 URL,比如检查 XMLHttpRequest 或者 Fetch 是否是跨站点请求,或者检测 HTTPS 的站点中是否包含了 HTTP 的请求。
用户交互
通常情况下,如果你要实现一个 UI 程序,操作系统会提供一个界面给你,该界面允许应用程序与用户交互,允许应用程序在该界面上进行绘制,比如 Windows 提供的是 HWND,Linux 提供的 XWindow,我们就把HWND和XWindow统称为窗口句柄。应用程序可以在窗口句柄上进行绘制和接收键盘鼠标消息。
渲染进程不能直接访问窗口句柄,所以渲染进程需要完成以下两点大的改变。
第一点,渲染进程需要渲染出位图。为了向用户显示渲染进程渲染出来的位图,渲染进程需要将生成好的位图发送到浏览器内核,然后浏览器内核将位图复制到屏幕上。
第二点,操作系统没有将用户输入事件直接传递给渲染进程,而是将这些事件传递给浏览器内核。然后浏览器内核再根据当前浏览器界面的状态来判断如何调度这些事件,如果当前焦点位于浏览器地址栏中,则输入事件会在浏览器内核内部处理;如果当前焦点在页面的区域内,则浏览器内核会将输入事件转发给渲染进程。
站点隔离(Site Isolation)
所谓站点隔离是指 Chrome 将同一站点(包含了相同根域名和相同协议的地址)中相互关联的页面放到同一个渲染进程中执行。
最开始 Chrome 划分渲染进程是以标签页为单位,也就是说整个标签页会被划分给某个渲染进程。但是,按照标签页划分渲染进程存在一些问题,原因就是一个标签页中可能包含了多个iframe,而这些iframe又有可能来自于不同的站点,这就导致了多个不同站点中的内容通过iframe同时运行在同一个渲染进程中。
因此 Chrome 几年前就开始重构代码,将标签级的渲染进程重构为 iframe 级的渲染进程,然后严格按照同一站点的策略来分配渲染进程,这就是 Chrome 中的站点隔离。
实现了站点隔离,就可以将恶意的 iframe 隔离在恶意进程内部,使得它无法继续访问其他 iframe 进程的内容,因此也就无法攻击其他站点了。
为什么要让他们跑在一个进程里面呢?
因为在一个渲染进程里面,他们就会共享 JS 的执行环境,也就是说 A 页面可以直接在 B 页面中执行脚本。因为是同一家的站点,所以是有这个需求的。