JS 沙盒隔离技术盘点与实战

本文的教学代码在 github.com/duheng1992/... ,欢迎大家批评指正,如果觉得好,还望给点个星星啦!😊

项目地址:monto-js-sandbox

本文系统梳理一下前端常见的 JavaScript 沙盒隔离技术,结合实战项目,带你深入理解各类沙盒的原理、优缺点与应用场景。

为什么需要 JS 沙盒?

在微前端、插件系统、在线编辑器、低代码平台等场景中,经常需要安全地运行第三方或不可信的 JavaScript 代码。沙盒(Sandbox)技术可以有效隔离运行环境,防止全局污染、数据泄露和恶意攻击。

Get started

npm install monto-js-sandbox

以下是一个基于 proxy 的简单沙箱实现示例,可用于安全地加载和执行第三方 JavaScript 代码:

js 复制代码
import { ProxySandbox } from 'monto-js-sandbox';

const sb = new ProxySandbox({
  rootElm: globalThis
});
const a = 333;
const scriptText = 'console.log("沙盒中的a: ", a);var a = 111;';
sb.execScript(scriptText);
console.log("父容器中的a: ", a)
sb.destroy();

1. Proxy 沙盒

技术原理

  • 利用 Proxy代理空对象作为全局变量,并传递白名单里的真实root的属性
  • 利用 with 语句来向代码块传递全局变量。
  • 通过 has、get、set 等钩子,实现对全局对象的"虚拟化"。
  • 可实现"伪私有"属性、只读沙盒等扩展。

伪代码

js 复制代码
const sandbox = new Proxy({}, {
  has(target, key) {
    // 隐藏下划线开头的属性
    if (key.startsWith('_')) return false;
    return true;
  },

  get(target, key) {
    // 白名单属性透传到真实 window
    if (typeof prop === 'string' && whiteList.has(prop)) {
      // 允许沙盒内访问 window、globalThis、self、top、parent 时返回代理自身,防止逃逸
      if (['window', 'globalThis', 'self', 'top', 'parent'].includes(prop)) {
        return receiver;
      }
      // 其他白名单属性透传
      return realWindow[prop];
    }
    // 其余属性在 {} 上隔离
    if (prop in target) {
      return target[prop];
    }
    return undefined;
  },
  
  set(target, key, value) {
    target[key] = value;
    return true;
  }
});

with (sandbox) {
  // 用户代码
}

优缺点

  • 优点:实现简单,性能好,灵活可扩展。
  • 缺点:无法彻底隔离全局对象,不能防御 globalThis、Function、eval 等绕过手段,存在原型链污染风险。

应用场景

  • 低风险的插件隔离
  • 需要灵活扩展的沙盒场景

qiankun(以及 single-spa 微前端沙箱体系)采用的 JS 沙箱方案,本质上和 Proxy 沙盒原理类似,即通过 Proxy+with 劫持全局变量访问,但它也无法彻底防御 Function('globalThis.foo = 1') 这种"全局标识符静态解析"的环境污染。

2. iframe 沙盒

技术原理

  • 利用 <iframe sandbox> 属性,浏览器原生实现强隔离。
  • 可通过 postMessage 实现主页面与沙盒通信。
  • 可配合 CSP、Referrer-Policy 等安全头部,进一步提升安全性。

架构示意

优缺点

  • 优点:隔离性最强,几乎无沙盒逃逸风险。
  • 缺点:性能开销大,通信复杂,无法直接操作主页面 DOM。

应用场景

  • 一般用于跨域场景
  • 运行完全不可信的第三方代码
  • 在线 IDE、低代码平台 (比如 码上掘金)

3. 快照沙盒(SnapshotSandbox)

技术原理

  • 激活时对全局对象做快照,执行后对比差异(diff)。
  • 销毁时还原所有被污染的全局属性。

伪代码

js 复制代码
class SnapshotSandbox {
  activate() {
    // 记录快照
    this.recordOriginGlobal(this.$root);
  }
  
  execScript(code) { 
    eval(code);
    // 记录 diff
    recordDiffPropsMap();
  }

  deactivate() {
    // 从 diff 还原root
    recoverOriginGlobal();
  }
}

优缺点

  • 优点:能还原全局环境,适合单实例串行运行。
  • 缺点:快照沙盒不是运行时隔离,而是"允许污染、事后还原",所以多实例并发时,作用域会被反复污染。

应用场景

  • 微前端子应用串行加载 或者子应用之间共生加载
  • 需要全局环境还原的场景

4. WebComponent 沙盒

技术原理

  • 利用 WebComponent + Shadow DOM 实现 DOM/CSS 隔离。
  • JS 作用域通过参数注入部分隔离,只暴露白名单变量。

伪代码

js 复制代码
class WebComponentSandbox {
    private avtive() {
        // 注册自定义元素(只注册一次)
        if (!customElements.get(tagName)) {
          customElements.define(tagName, class extends HTMLElement {});
        }

        // 创建元素并挂载
        this.element = document.createElement(tagName);
        container.appendChild(this.element);

        // 创建 Shadow DOM
        this.shadowRoot = this.element.attachShadow({ mode: 'open' });
    }
    
    execScript() {
      const fn = new Function('');
    }
}

优缺点

  • 优点:DOM/CSS 隔离彻底,灵活可控。
  • 缺点:JS 作用域隔离有限,需谨慎注入变量。

应用场景

  • 需要样式隔离的插件系统,往往和 proxy 结合使用
  • 微前端 UI 组件隔离

5. QuickJS + WASM 沙盒

技术原理

  • 基于 quickjs-emscripten 的 WASM 虚拟机,主环境与沙盒环境完全隔离。
  • 通过 API 创建上下文、对象、函数,执行代码,手动管理内存。

代码片段

js 复制代码
class QuickJSSandbox {
  private async active() {
    this.QuickJS = await getQuickJS();
    this.vm = this.QuickJS.newContext();
    // 桥接 console.log 到主环境
    const vm = this.vm;
    // const qjs = this.QuickJS;
    // 在 QuickJS 沙盒环境中桥接(注入)主环境的 console.log 方法,让沙盒内的 JS 代码可以安全地调用 console.log,并把日志输出到主环境的控制台。
    const consoleObj = vm.newObject();
    const logFn = vm.newFunction('log', (...args: any[]) => {
      // dump 可将 QuickJS 值转为主环境值
      console.log('[沙盒]', ...args.map((arg) => vm.dump(arg)));
    });
    vm.setProp(consoleObj, 'log', logFn);
    vm.setProp(vm.global, 'console', consoleObj);
    // 这里应该加上,不然会内存泄漏
    consoleObj.dispose();
    logFn.dispose();
  }
  
  async execScript(scriptText: string): Promise<any> {
    const result = this.vm.evalCode(scriptText);
  }
}

优缺点

  • 优点:隔离性最强,支持多实例并发,适合运行不可信 JS。
  • 缺点:依赖 WASM,体积较大,API 使用门槛高。沙盒内 JS 不能直接访问 DOM、window、document 等浏览器原生对象,只能通过你暴露的接口与主页面通信。同时对于内存管理要求较高。

应用场景

  • 在线 IDE、沙盒执行环境
  • 后端安全 JS 执行、插件系统

项目亮点

  • 多种沙盒方案一站式体验:Proxy、iframe、快照、WebComponent、QuickJS+WASM 全覆盖。
  • 丰富的实战案例:每种沙盒均有独立示例,便于对比和学习。
  • 安全性与性能兼顾:适合不同场景灵活选型。
  • 完善的文档与架构图:助力快速上手与二次开发。

monto-js-sandbox 项目已开源,欢迎 Star、Fork、交流与贡献!

相关推荐
FairyDiana几秒前
【JavaScript】一篇文章,带你拿捏闭包
前端·javascript
前端日常开发5 分钟前
深入浅出 Vue 3 setup 函数的功能与优势
前端
zhanshuo9 分钟前
3分钟搞定!ASP.NET登录时间记录实战:安全又高效的用户体验优化
前端
用户276920244534611 分钟前
基于 Tauri + Vue3 的现代化新流串口调试助手 v2
前端·rust
Hockor12 分钟前
写给前端的 Python 教程二
前端·后端·python
yinke小琪12 分钟前
微信小程序/H5 调起确认收款界面
前端
慰尘12 分钟前
npm包从创建到发布的基础流程概述
前端·开源
埃及14 分钟前
探索微前端架构:多种实现方式与实践思考
前端·javascript
GIS之路14 分钟前
OpenLayers 地图标注之聚合标注
前端