JavaScript沙箱通过作用域隔离限制代码访问范围,防止污染全局环境;常用IIFE或new Function实现轻量隔离,配合冻结/Proxy控制全局对象,但无法防御原型污染等高级逃逸,生产环境应优先使用iframe sandbox或Web Worker。

JavaScript 中利用作用域实现沙箱隔离,核心是**限制代码可访问的变量和函数范围,防止其读写全局环境或污染外部状态**。这不是浏览器原生的完整沙箱(如 iframe 或 Web Worker),而是轻量级、基于执行上下文的作用域隔离,常用于插件系统、模板渲染、配置脚本等场景。
用函数作用域包裹执行代码
最基础也最常用的方式:将待执行的代码封装进一个立即执行函数(IIFE),只传入明确允许访问的变量,不暴露 window、globalThis 等全局对象。
例如:
function createSandbox(globalAPI = {}) {
const safeGlobal = { ...globalAPI }; // 显式提供白名单 API
return function (code) {
// 注意:eval 在严格模式下无法访问外层变量,需在非严格模式下使用
// 更安全的做法是用 new Function
const fn = new Function('global', 'return (' + code + ')');
return fn(safeGlobal);
};
}
const runInSandbox = createSandbox({ Math, JSON });
runInSandbox('Math.sqrt(16)'); // → 4
runInSandbox('window.location'); // ReferenceError: window is not defined
用 new Function 替代 eval
eval 会继承当前作用域链,容易意外访问闭包变量;而 new Function 创建的函数**总是在全局作用域(但可控制参数)中执行,天然更隔离**。
立即学习“Java免费学习笔记(深入)”;
- 它的参数名就是函数的形参,所有变量必须显式传入
- 无法直接访问外层函数的局部变量(除非手动绑定)
- 避免了
eval的安全与性能问题
冻结或代理全局对象做“只读沙箱”
若需模拟部分全局环境(比如提供 console.log),可用 Object.freeze 或 Proxy 控制访问行为:
const fakeGlobal = {
console: {
log: (...args) => console.log('[SANDBOX]', ...args)
},
Date: Date,
Number: Number
};
Object.freeze(fakeGlobal); // 防止被篡改
// 或用 Proxy 拦截非法访问
const sandboxGlobal = new Proxy(fakeGlobal, {
get(target, prop) {
if (prop in target) return target[prop];
throw new ReferenceError(`Access denied: ${prop}`);
}
});
结合 with(不推荐)或模块化模拟隔离
with 虽能临时注入作用域,但已被严格模式禁用,且易导致性能和调试问题,**应避免使用**。
现代更推荐方式是:把沙箱逻辑封装为模块,用 ES Module 的词法作用域天然隔离,再通过动态 import() 加载受信脚本(注意仍需校验来源)。
例如加载一个仅含纯函数的配置脚本:
// config.js(需确保内容可信)
export const timeout = 5000;
export const retry = 3;
// 主程序中
async function loadConfig() {
const mod = await import('./config.js');
return { timeout: mod.timeout, retry: mod.retry }; // 自动隔离,无副作用
}
不复杂但容易忽略:真正安全的沙箱不能只靠作用域——它无法阻止原型污染、Function.constructor 构造、setTimeout 回调逃逸等。生产环境建议优先用 <iframe sandbox></iframe>、Web Worker 或服务端 V8 isolate。


















