【前后端】沙箱机制
概念
- 沙箱机制的核心目标:限制不可信代码的能力范围,保护主程序和系统安全。
- 不是所有的沙箱机制都差不多,其实因平台、语言、目标不同而差异巨大。
有的沙箱是通过权限声明(如浏览器扩展 Manifest)
有的是通过系统级隔离(如 Docker、虚拟机)
有的是通过语言级限制(如 Python 的 restricted exec)
平台/语言 | 沙箱机制 | 原理 | 特点 |
---|---|---|---|
Node.js | vm 模块、子进程、受控 API | 创建隔离上下文或进程 | 灵活但不绝对安全 |
浏览器 | iframe 沙箱、CSP、Web Worker | 限制 DOM、网络、脚本执行 | 安全性高但功能受限 |
Python | exec + 限制 globals、Pyodide | 控制执行环境 | 不推荐在生产使用 |
Docker | 容器隔离 | 内核级命名空间和权限控制 | 强隔离,适合服务级沙箱 |
操作系统级 | 虚拟机、用户权限、SELinux | 系统级资源隔离 | 安全性最高但成本大 |
浏览器扩展 | Manifest 权限声明 + 沙箱页面 | 限制 API 和访问范围 | 通过声明控制能力 |
- 插件沙箱机制是指:在运行插件时,限制它的权限和作用范围,防止它对主程序或系统造成破坏或干扰。
插件是外部代码,可能不可信
插件可能会修改全局变量、污染环境、阻塞主线程
插件可能会访问敏感资源(如文件系统、网络)
nodejs常见沙箱实现方案
- vm 模块(轻量沙箱)
优点:快速、内存隔离
缺点:无法完全阻止访问 Node API(如 require)
const vm = require('vm');
const sandbox = { console };
vm.createContext(sandbox);
vm.runInContext('console.log("Hello")', sandbox);
- 子进程或 Worker Threads(进程级隔离)
优点:真正隔离内存和执行环境
缺点:通信复杂、性能开销略高
const { fork } = require('child_process');
const child = fork('./plugin.js');
- 受控 API 注入(逻辑沙箱)
优点:简单易控
缺点:插件仍在主进程运行,无法防止恶意代码
plugin.run({ log, renderMarkdown, getConfig });
插件的沙箱机制
- 判断是否做到位
插件是否运行在主进程中?是否可以访问 process, fs, require 等?
插件是否可以修改主程序的变量或状态?
插件是否只能使用你提供的 API(比如 renderMarkdown, log, getConfig)?
插件出错是否会影响整个 CLI 工具运行? - 实现
推荐:子进程执行 使用 child_process.fork() 或 worker_threads 运行插件代码 隔离内存和执行环境
限制多:VM 虚拟机模块使用 Node.js 的 vm 模块运行插件代码,限制访问变量
const vm = require('vm');
const code = fs.readFileSync(pluginPath, 'utf-8');
const sandbox = { module: {}, console };
vm.createContext(sandbox);
vm.runInContext(code, sandbox);
最常见:限制 API 注入 插件只接收你提供的 API,不暴露主程序对象
const plugin = require(pluginPath);
const sandboxAPI = {renderMarkdown,log,getConfig
};
plugin.run(sandboxAPI); // 插件只能用你给的 API
高级方式,适用于大型系统:权限控制 插件声明需要的权限(如读文件、写文件),主程序决定是否允许