沙箱隔离调研

主要设计

整体设计

  • 借鉴 with 的实现效果,在 webpack 编译打包阶段为每个子应用代码包裹一层代码 或者 通过 new Function 拼接代码,创建一个闭包,传入自己模拟的 window、document、location、history 等全局对象。
    • 在模拟的 Context 中,new 一个 iframe 对象,提供一个和宿主应用空的(about:blank) 同域 URL 来作为这个 iframe 初始加载的 URL(空的 URL 不会发生资源加载,但是会产生和这个 iframe 中关联的 history 不能被操作的问题,这时路由的变换只支持 hash 模式),然后将其下的原生浏览器对象通过 contentWindow 取出来(因为 iframe 对象天然隔离,这里省去了自己 Mock 实现所有 API 的成本)。
      • 取出对应的 iframe 中原生的对象之后,继续对特定需要隔离的对象生成对应的 Proxy,然后对一些属性获取和属性设置,做一些特定的实现(比如 window.document 需要返回特定的沙箱 document 而不是当前浏览器的document 等)。
        • 为了文档内容能够被加载在同一个 DOM 树上,对于 document,大部分的 DOM 操作的属性和方法仍旧直接使用宿主浏览器中的 document 的属性和方法处理等。

          基本原理

          1. js沙箱原理:沙箱的目的其实就是隔离变量,代理某些变量,防止污染宿主环境. 在浏览器中,我们可以利用 js 闭包的能力,利用变量作用域去模拟一个沙箱环境,最简单的例子:这段代码的输出一定是 { createElement: "***" }, 而不是浏览器原生的 document
            1. notion image
          1. 难点:如何模拟浏览器原生window? 有两个方案,一是根据 ECMA 规范实现这一堆的浏览器原生对象,显然这个成本太高.所以这里有个取巧的办法,我们可以创建一个 iframe并设置src="about:blank",这个时候可以确保 url 同域,也不会发生资源加载.然后取出 iframe 对应的 contentWindow,利用其天然隔离特性,省去了自己实现的成本.
            1. notion image
              notion image

          对比其他方案

          1. snapshotSandbox主要用于不支持 es6 Proxy的浏览器,并且也只适合单实例子应用.snapshotSandbox会污染全局window,但是可以支持不兼容Proxy的浏览器。
            1. proxySandbox 代理沙箱其代理对象来自普通对象 fakeWindow,然后将 window 上的 documentlocationtopwindow 等属性拷贝一份到 fakeWindow优点是不会污染全局 window,缺点是没有 iframe.contentWindow 的隔离那么彻底.
              1. 基于 Web Worker,webAssembly,iframe 实现沙箱参考文章: https://cloud.tencent.com/developer/article/1887036
                1. 基于客户端 JavaScriptCore 实现沙箱这个需要客户端(iOS, android)配合 https://www.jianshu.com/p/a9d72a36456d

                  主要流程图

                  notion image

                  Reference

                  notion image
                  https://docs.qq.com/pdf/DWXB5SXhOSFVTemh3

                  © Jiyu Shao 2018 - 2025