JavaScript沙箱通过隔离执行环境防止第三方代码污染宿主,核心方案包括:eval()/new Function()因可访问全局对象存在逃逸风险;iframe提供独立文档和全局对象,实现强隔离,但有性能开销和跨域通信限制;Web Workers以线程级隔离保障安全且不阻塞UI,但无法直接操作DOM;而结合Proxy与with语句可构建轻量级软沙箱,通过拦截属性访问控制权限,适用于高性能、细粒度控制场景。

JavaScript的沙箱环境核心在于提供一个隔离的执行空间,让第三方代码在其中运行,而无法直接访问或修改宿主环境的全局对象、DOM或其他敏感资源。这就像给代码一个独立的“房间”,它可以在里面自由活动,但不能随意打开通往其他房间的门,更不能破坏房子结构。通过这种方式,我们能有效地避免恶意或有缺陷的第三方代码对应用造成全局污染或安全威胁。
要实现JavaScript的沙箱环境,有多种策略,从轻量级到重量级,各有其适用场景。最常见的思路是利用语言特性或浏览器提供的隔离机制。
一种直接但相对不安全的做法是尝试通过
eval()
new Function()
window
this
更可靠的隔离手段则依赖于浏览器提供的更强的隔离机制:
iframe
Web Workers
iframe
Web Workers
立即学习“Java免费学习笔记(深入)”;
此外,对于需要在同一线程内进行“软沙箱”处理的场景,可以利用ES6的
Proxy
with
with
当我们在JavaScript中使用
eval()
new Function()
eval()
eval()
let secretToken = '...'
eval('console.log(secretToken)')window
eval('window.location.href = "malicious.com"')new Function()
new Function('console.log(window.document)')()this
new Function()
所以,如果第三方代码的来源不可信,或者你对代码的内容没有完全的掌控,直接使用
eval()
new Function()
iframe
Web Workers
iframe
iframe
window
document
iframe
window.location
Array.prototype
iframe
iframe
iframe
iframe
然而,
iframe
iframe
iframe
postMessage
iframe
iframe
Web Workers
self
Web Workers
但
Web Workers
postMessage
Web Workers
利用
Proxy
with
iframe
Web Workers
首先,我们得聊聊
with
with
function createSandboxedFunction(code, context) {
// context 是我们希望沙箱代码能够访问的属性集合
// 例如 { console: console, fetch: fetch }
const wrappedCode = `with (sandboxContext) { ${code} }`;
// 注意:这里的 new Function 会在全局作用域创建函数
// 但 with 语句会先查找 sandboxContext,然后才是全局
return new Function('sandboxContext', wrappedCode);
}
const sandboxContext = {
// 只暴露我们希望第三方代码访问的API
log: console.log,
add: (a, b) => a + b
};
try {
const sandboxedFunc = createSandboxedFunction('log("Hello from sandbox!"); console.log(add(1, 2)); alert("Trying to alert!");', sandboxContext);
sandboxedFunc(sandboxContext);
} catch (e) {
console.error("Sandbox execution error:", e);
}
// 这里的 alert 不会执行,因为 sandboxContext 中没有 alert然而,仅仅依靠
with
window
globalThis
Proxy
Proxy
get
set
has
Proxy
function createSecureSandbox(code, allowedGlobals = {}) {
const sandboxGlobal = { ...allowedGlobals }; // 初始允许的全局变量
// 创建一个Proxy来拦截对sandboxGlobal的访问
const proxyHandler = {
has(target, key) {
// 阻止访问一些敏感的全局属性
if (['window', 'document', 'location', 'eval', 'Function', 'alert', 'fetch', 'XMLHttpRequest'].includes(key)) {
console.warn(`Attempted to access restricted global: ${key}`);
return false; // 假装这些属性不存在
}
return key in target || key in globalThis; // 优先从沙箱上下文查找,然后是真实的全局
},
get(target, key, receiver) {
if (['window', 'document', 'location', 'eval', 'Function', 'alert', 'fetch', 'XMLHttpRequest'].includes(key)) {
console.warn(`Attempted to read restricted global: ${key}`);
return undefined; // 返回 undefined 或抛出错误
}
// 如果沙箱上下文有,就返回沙箱的
if (key in target) {
return Reflect.get(target, key, receiver);
}
// 否则,从真实的全局对象中获取(如果允许)
// 这里可以根据需要,进一步限制对globalThis的访问
return Reflect.get(globalThis, key, receiver);
},
set(target, key, value, receiver) {
if (['window', 'document', 'location'].includes(key)) {
console.warn(`Attempted to write to restricted global: ${key}`);
return false; // 阻止写入敏感全局属性
}
// 允许写入到沙箱上下文
return Reflect.set(target, key, value, receiver);
}
};
const sandboxedContext = new Proxy(sandboxGlobal, proxyHandler);
// 将代码包装在一个立即执行函数中,并将沙箱上下文作为参数传入
// 这样,代码中的this和全局访问都将被限制在sandboxedContext内
const wrappedCode = `
(function(global) {
with (global) {
${code}
}
})(sandboxedContext);
`;
// 使用new Function来执行包装后的代码
// 注意:这里的new Function仍然在全局作用域创建,但内部通过with和Proxy进行了限制
return new Function('sandboxedContext', wrappedCode);
}
// 示例用法
const userCode = `
console.log('Hello from sandboxed code!');
var myVar = 'local';
console.log('myVar:', myVar);
// 尝试访问被限制的全局对象
try {
console.log('window:', window);
} catch (e) {
console.error('Error accessing window:', e.message);
}
// 尝试修改全局对象
document.body.style.backgroundColor = 'red';
// 尝试访问允许的全局
console.log('Allowed value:', allowedValue);
`;
const allowedAPIs = {
console: console, // 允许访问宿主的console
allowedValue: 123 // 自定义一个允许访问的全局变量
};
try {
const executeSandbox = createSecureSandbox(userCode, allowedAPIs);
executeSandbox(allowedAPIs); // 传入初始允许的全局变量
} catch (e) {
console.error('Execution failed:', e);
}这个
Proxy
with
Proxy
sandboxedContext
window
document
with
sandboxedContext
Proxy
proxyHandler
以上就是什么是JavaScript的沙箱环境实现原理,以及如何安全地执行第三方代码以避免全局污染?的详细内容,更多请关注php中文网其它相关文章!
每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。
Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号