跳转到内容

Flowise 的沙箱安全:vm2 隔离、E2B 回退与安全 HTTP 封装

学习目标

  • 理解 Flowise 的三层沙箱安全模型:vm2 本地隔离、E2B 云端沙箱、HTTP 安全封装
  • 掌握 NodeVM 的配置选项与安全边界
  • 了解 SSRF 防护的 hostname deny list 机制

前置知识

本章为项目特定的工程实践,无外部前置知识要求。


项目实践

三层沙箱模型

第一层:vm2 NodeVM 隔离

executeJavaScriptCode 函数是代码执行的核心:

const defaultNodeVMOptions = {
console: 'inherit', // 继承控制台输出
sandbox, // 沙箱变量
require: {
external: {
modules: deps, // 允许的 npm 模块白名单
transitive: false // 禁止传递依赖
},
builtin: builtinDeps, // 内置模块白名单
mock: secureWrappers // 替换 HTTP 库为安全封装
},
eval: false, // 禁止 eval
wasm: false, // 禁止 WebAssembly
timeout: timeoutMs // 超时控制(默认 5 分钟)
}
const vm = new NodeVM(finalNodeVMOptions)
const response = await vm.run(`module.exports = async function() {${code}}()`)

沙箱对象:阻断危险模块

const sandbox = {
$input: input, // 输入数据
$vars: preparedVars, // 全局变量
$flow: flowConfig, // 流程配置(sessionId, chatId 等)
util: undefined, // 禁止 util
Symbol: undefined, // 禁止 Symbol
child_process: undefined, // 禁止子进程
fs: undefined, // 禁止文件系统
process: undefined // 禁止进程对象
}

第二层:E2B 云端沙箱

当设置了 E2B_APIKEY 环境变量时,Flowise 自动切换到 E2B 云端沙箱:

if (useSandbox && process.env.E2B_APIKEY) {
→ 使用 E2B Sandbox(完全隔离的容器)
} else {
→ 使用 vm2 NodeVM(进程内隔离)
}

E2B 沙箱的优势

  • 完全隔离的容器,vm2 已知漏洞(CVE-2023-29017)无法利用
  • 独立的文件系统和网络环境
  • 可配置的资源限制(CPU、内存、网络)

E2B 沙箱的执行方式

  1. 将用户代码序列化为字符串
  2. 通过 E2B API 发送到远程容器
  3. 在容器中执行,返回结果

第三层:HTTP 安全封装

vm2 中的 HTTP 请求(axios、node-fetch)被替换为安全封装:

secureWrappers['axios'] = async (config) => {
await checkDenyList(config.url) // 检查 hostname deny list
return secureAxiosWrapper(config) // 使用安全 fetch
}
secureWrappers['node-fetch'] = async (url, options) => {
return secureFetch(url, options) // 安全 fetch
}

secureFetch 的防护措施

  • 检查 URL 是否为内网地址(SSRF 防护)
  • 跟随重定向时重新检查目标地址
  • 限制请求方法和头信息

checkDenyList

  • 阻止访问已知不安全的 hostname
  • 阻止访问内网地址(127.0.0.1、10.x.x.x、192.168.x.x 等)

问题与规避

vm2 的已知漏洞

问题:vm2 存在多个已知逃逸漏洞(如 CVE-2023-29017),攻击者可能通过精心构造的代码逃逸沙箱。

对策

  • 不要在生产环境中执行不受信任的代码
  • 启用 E2B 云端沙箱作为安全回退
  • 限制可用的 npm 模块(require.external.modules 白名单)
  • 设置合理的 timeout(防止无限循环消耗资源)

SSRF 攻击向量

问题:用户自定义函数可能尝试访问内网服务(如 http://169.254.169.254 获取 AWS 元数据)。

对策

  • 所有 HTTP 请求通过 secureFetch,自动检测并阻止内网地址
  • checkDenyList 维护已知的危险 hostname 列表
  • 禁止使用原始的 http/https 模块(不在白名单中)

资源耗尽

问题:恶意代码可能通过无限循环或大内存分配耗尽服务器资源。

对策

  • NodeVM 的 timeout 选项限制执行时间(默认 5 分钟)
  • 可通过 SANDBOX_TIMEOUT 环境变量覆盖
  • E2B 沙箱有独立的资源限制配置

设计取舍

vm2 vs 其他沙箱方案

方案安全性性能复杂度
vm2 NodeVM中(有已知漏洞)高(进程内)
E2B Sandbox高(容器隔离)中(网络延迟)高(需要 API Key)
Node.js vm低(无隔离)最高最低
Web Workers高(浏览器隔离)
Docker 容器最高低(容器启动)

Flowise 的 vm2 + E2B 双策略是务实的选择:

  • 开发环境/可信代码:vm2 足够,零延迟
  • 生产环境/不可信代码:E2B 提供完全隔离

模块白名单 vs 完全隔离

方案优势代价
白名单灵活,允许有用的模块需要维护白名单,可能遗漏危险模块
完全隔离最安全用户代码功能受限,实用性低

Flowise 选择白名单,因为:

  • 用户需要 node-fetchaxios 等 HTTP 库调用 API
  • lodashmoment 等工具库在数据处理中常用
  • 通过安全封装(secureWrappers)可以在保留功能的同时防护风险

参考来源