微沙箱需从执行模型源头切断污染路径:一、剥离标准库,用null原型重建全局对象图并禁用动态能力;二、冻结所有对象原型链、隔离作用域链、禁用隐式this绑定;三、以白名单函数替代标准模块能力;四、通过三段测试代码验证免疫性。

要从零构建一个完全不依赖标准库、且能完美防御原型链污染等攻击的微沙箱,核心不是堆砌隔离层,而是从执行模型源头切断污染路径——这意味着你得放弃“在现有运行时里加锁”,转而设计一个“没有锁孔”的执行环境。
一、彻底剥离标准库:用裸 JavaScript 语义重建沙盒边界
标准库(如 Object.prototype、Function.prototype、Array.prototype)是污染主入口。真正的“不依赖”,不是禁用 require 或删掉 fs,而是让沙箱内根本不存在可被篡改的原型链。
- 不用
Object.create(null)仅作起点,而要用它初始化整个全局对象图:所有内置对象(String、Number、JSON等)都必须从null原型创建,并显式挂载最小必要方法 - 禁止访问任何构造器(
Function、Object、Array),只提供预编译的、不可配置的工具函数(如safeParseInt、safeJSONParse) - 禁用所有动态能力:
eval、Function构造器、with、__proto__、setPrototypeOf、defineProperty(除非白名单属性)
二、防御污染的关键:冻结原型链 + 隔离作用域链
原型链污染本质是利用属性赋值穿透到顶层原型。防御不是“检测污染”,而是让穿透本身失效。
- 所有沙箱内对象(包括全局对象)必须调用
Object.freeze()和Object.seal(),且在创建后立即锁定,不允许后续扩展 - 使用
vm.Script(非vm.runInNewContext)配合自定义context,确保每次执行都从干净作用域开始,不复用任何上下文引用 - 禁用
this在非方法调用中的隐式绑定(例如(function(){})()中的this必须为undefined,而非全局对象)
三、不靠 Node.js 标准模块:用纯 JS 实现最小运行时能力
所谓“不依赖标准库”,是指不调用 fs.readFileSync、path.join 等,但沙箱仍需基础能力。解决方案是:把能力变成“数据驱动”的白名单函数。
- 文件读取?只允许传入预注册的文件 ID(如
"config.json"),对应内存中已加载的只读 JSON 对象,无路径解析、无遍历 - 定时任务?只暴露
setTimeout(fn, ms),且ms严格限制在 [1, 5000],回调函数必须是沙箱内定义的闭包,无法逃逸 - 网络请求?完全禁用。若必须,只允许通过预设的
fetchData(id)接口,id映射到服务端已审核的 API 模板,参数经 JSON Schema 校验后透传
四、验证是否“完美防御”:三个硬性检查点
完成构建后,用以下三段代码测试——任一段能成功执行,说明沙箱未达标:
-
Object.prototype.polluted = 1; console.log({}.polluted);→ 应报错或输出undefined -
this.constructor.constructor("return process")()→ 应抛出ReferenceError或TypeError -
let a = {}; a.__proto__.x = 1; console.log({}.x);→ 应始终为undefined
能做到这三点,就不是“加固了的沙箱”,而是“天生免疫的执行单元”。它不靠拦截,而靠缺失;不靠防御,而靠不可达。这才是微沙箱该有的样子。











