Web Worker 是前端安全沙箱最主流方案,因其线程隔离、无 DOM 访问、可控通信及可终止特性;需禁用 eval/Function、静态扫描关键词、重写内置对象、超时控制,并推荐 Comlink 封装通信。

在 Web Worker 中动态执行用户脚本,是目前前端实现安全沙箱最主流、最可行的方案之一。它天然规避了 DOM 访问、主线程阻塞和全局污染等高危风险,关键在于如何正确构造执行上下文、限制能力边界,并防止代码逃逸。
为什么 Web Worker 适合做沙箱
Worker 运行在独立线程,与主线程完全隔离:
- 无法访问 window、document、localStorage 等任何浏览器 API
- 不能直接操作 DOM 或触发 UI 渲染,从根本上杜绝 XSS 和界面篡改
- 主线程可通过 postMessage 发送数据,Worker 只能回传序列化结果,通信通道可控
- 可随时调用 worker.terminate() 强制中止,有效防御死循环或无限递归
安全执行用户脚本的核心做法
不推荐直接 eval 或 new Function(code) 执行原始字符串——即便在 Worker 内,仍可能通过原型链、constructor、Function.constructor 等方式绕过限制。应主动剥离危险能力:
- 使用 strict 模式 + 显式作用域封装:将用户代码包裹在函数体内,只暴露白名单参数(如
data、utils),禁止隐式访问全局对象 - 禁用危险构造器:在运行前对
code字符串做静态扫描,拦截Function、eval、setTimeout、fetch、XMLHttpRequest等关键词(简单但有效) - 重写内置对象行为:例如把
Object.prototype.constructor设为undefined,或冻结Function.prototype,防反射逃逸 - 超时控制:在 Worker 内用 AbortController 或计时器配合
try...catch捕获长耗时,主动 throw 中断
推荐的工程化结构
采用 Comlink 封装通信接口,提升类型安全与开发体验:
- 主线程创建 Worker 实例,通过
Comlink.wrap()获取远程代理对象 - Worker 脚本中
Comlink.expose()一个 API 对象,仅暴露runUserCode(code, inputData, context)方法 -
context是预置的工具集(如utils: { sum, formatDate }),全部由主进程注入,不继承任何全局环境 - 用户代码中只能调用
utils.xxx,无法访问this、arguments或globalThis
实际注意事项与避坑点
看似简单,落地时容易忽略细节:
- Worker 脚本本身必须是独立文件或合法 Blob URL;若用字符串动态生成,需确保 MIME 类型为
application/javascript,否则现代浏览器会拒绝执行 - 传递给 Worker 的数据需可序列化(不能含函数、Symbol、Map/Set 等),复杂结构建议先
JSON.stringify后再解析 - 频繁创建/销毁 Worker 有开销,可考虑复用 Worker 实例或实现轻量级任务队列,避免内存泄漏
- 注意跨域限制:Worker 加载的脚本必须同源,若用 Blob URL 则无此问题

















