前端沙箱是什么? 怎么实现沙箱环境?


前端沙箱是什么?怎么实现沙箱环境?
● 沙箱:沙箱是一种安全机制,为运行中的程序提供隔离环境,能够安全的执行不受信任的代码,且不影响外部实际代码影响的独立环境。
● 场景:
  ○ 低代码平台中,用户提交的各种事件处理逻辑
  ○ 在线代码编辑器,比如 掘金
  ○ 插件,比如 figma
  ○ 开发/生产环境隔离
● 预防:不在预期内的副作用、全局污染、篡改ui、网络攻击。。。。
● 问题拆解:
  ○ 可执行:能够正常执行用户提供的脚本;
    ■ eval、new function动态 script 标签动态import静态编译webworker 等等
隔离沙箱环境内不可访问全局环境沙箱必须检测并预防哪些不在预期内的代码行为
数据隔离上下文接口隔离
模拟提供必要的严格受控的上下文
实现
with在当前作用域顶端再加一个作用域(vue 源码中就通过这种方式,在render 函数注入上下文数据),可用于模拟上下文环境
问题只能保证能访问啥”,不能有效隔离环境
with + proxy可以实现只允许访问命中上下文及白名单内的数据不允许访问其它数据
问题全局对象 document 只允许访问其中部分接口或者接口影响范围需要做限制
with + proxy + iframeiframe 可以创造一个独立浏览器主页面但完整的执行上下文环境能完美提供与主页面隔离的 bomdom 接口
<iframe sandbox="allow-scripts" src="about:blank"></iframe>
为什么 iframe 能确保安全
  a. h5 新出的 sandbox 可以限制iframe 权限例如默认不允许执行脚本等

 sandbox 基础上主页面与 iframe 页面之间可以限制为只通过 postMessage 接口通讯这个接口的好处在于
只关心明确注册的事件
事件参数会被序列化之后才传输在对面再反序列化成对象形式这也就相当于深克隆了不必担心对象操作的副作用(例如,通过 Object.defineProperty)
例如可以基于 postMessage + sandbox 属性实现有限度的 fetch 接口限制动态加载数据的域名白名单实现既要又要
how看示例代码
 proxy 等实现一个独立上下文环境问题有不少沙箱逃逸方法例如
// 创建一个新的全局函数
(()=>{}).constructor('','alert("abc")')();

// 通过原型链
a.b.__proto__.toString=function (){/* 危险代码 */}
a.b.toString()
    ■ 咋办:
      ● 静态代码分析:基于 js 的动态性,这必然不是一个好方案,但目前社区也没有更好的解决方案了
      ● iframe 隔离在安全域名,参考 juejin
● 再扩展开来:
  ○ qiankun 也是基于 iframe 实现的沙箱环境,有相关经验的同学可以看看
  ○ 在服务端,用安全环境运行浏览器,参考 Browserling
  ○ 自定义浏览器,例如微信公众号浏览器,or 小程序运行时,or 一些 hybrid app

● nodejs 中的沙箱:node 中安全泄露带来的问题更大,环境隔离需求更强
  ○ 应用:云函数、webide、LeetCode 等
  ○ 方案:
    ■ 使用 VM 模块,动态编译,沙箱、and 执行代码
const vm = require('vm');
const script = new vm.Script('m + n');
const sandbox = { m: 1, n: 2 };
const context = new vm.createContext(sandbox);
script.runInContext(context);
    ■ 但 vm 并不安全,例如:
const vm = require("vm");
const script = new vm.Script(
  'this.constructor.constructor("return process")().stdout.write("fwe") '
);
const sandbox = {};
const context = vm.createContext(sandbox);
script.runInContext(context);
({}.toString());

    ■ 使用扩展模块 vm2 —— 支持有限的上下文接口

浏览器处理 100KB 的 JS 文件与 100KB 的图片文件,那种更快?
解题:
● 初阶:
  ○ 图片文件更快,因为 JS 除了占用消耗网络传输时间之外,还需要经过解析、解释、执行阶段;而图片则只需要解编码即可
● 中阶:
  ○ 原理
    ■ js:网络加载、解析成 ast、编译成字节码、执行,并且由于是第一次加载,JIT 基本没有介入优化的机会
    ■ 图片:网络加载、解编码、合成渲染,且解码算法(针对 PNG、JPG 等常见格式)通常已经写进 GPU 硬件,可以实现硬件级别的解码,速度会非常非常快

![](https://cdn.nlark.com/yuque/0/2022/png/26698409/1661269027765-b2e19cbb-7b19-4102-8a14-aacc72965ded.png?x-oss-process%3Dimage%2Fresize%2Cw_1500%2Climit_0)

  ○ 性能优化:减少 js 代码量比多媒体资源体积,有价值的多
    ■ 网络:
      ● 按需加载(思考一下,code split 有没有优化效果)
      ● 代码最小化 & 合并 & function concat & gzip 压缩
      ● Tree-Shaking & dce
      ● 。。。
    ■ 解析:尽可能少
    ■ 执行:
      ● 减少同步 IO 接口调用(xhr 的同步模式、dom 接口、)
      ● 大任务拆分
      ● 使用 webworker
      ● 节流
    ■ JIT 优化:
      ● 保持数据结构不变
      ● 保持函数参数结构不变

最后更新于

这有帮助吗?