python

关注公众号 jb51net

关闭
首页 > 脚本专栏 > python > Python 调用 Node.js沙箱

Python 调用 Node.js vm2 沙箱实战教程

作者:ZHANG13HAO

本文提供了两种Python调用Node.js vm2沙箱执行不安全JS代码的实用方案,方案A采用子进程方式,方案B采用RPC长连接方式,适合高频调用场景,下面可以了解一下

你要的是 Python 作为主语言,调用 Node.js 里的 vm2 沙箱执行不安全 JS 代码,用 ** 胶水层(胶水语言 / 跨语言通信)** 实现,我给你两套最实用、可直接上线的方案:

核心需求

  1. Python 调用 JS
  2. JS 内部用 vm2 安全沙箱 执行不可信代码
  3. 跨语言通信(胶水)
  4. 完整可运行代码

我直接给你 最稳定、生产可用 的两套方案:

先准备环境

1. 创建项目

mkdir python-vm2
cd python-vm2

2. 安装依赖

# 安装 vm2
npm init -y
npm install vm2

# Python 无需额外安装库(内置 subprocess)

方案 A:最简胶水方案(Python 子进程调用 Node)

原理:Python 启动一个 Node 子进程,把代码传给 Node,Node 用 vm2 执行后把结果返回给 Python。最简单、最安全、无依赖。

1. 新建 Node 胶水脚本:runner.js

const { VM } = require('vm2');
// 从命令行接收 Python 传过来的 JS 代码
const userCode = process.argv[2] || '';
try {
    // 创建安全沙箱
    const vm = new VM({
        timeout: 1000,
        allowAsync: false,
        sandbox: {
            // 你可以给沙箱开放安全变量
            PI: 3.14159
        }
    });
    // 执行代码
    const result = vm.run(userCode);
    // 返回结果给 Python
    console.log(JSON.stringify({ success: true, data: result }));
} catch (err) {
    // 错误返回
    console.log(JSON.stringify({ success: false, error: err.message }));
}

2. 新建 Python 调用脚本:main.py

import subprocess
import json
import sys
def run_js_in_vm2(js_code: str):
    """
    Python 胶水函数:调用 Node.js + vm2 执行不安全 JS 代码
    """
    try:
        # 调用 node runner.js "代码"
        result = subprocess.run(
            [sys.executable.replace("python", "node"), "runner.js", js_code],
            capture_output=True,
            text=True,
            encoding="utf-8",
            timeout=3
        )
        # 解析返回结果
        output = result.stdout.strip()
        return json.loads(output)
    except Exception as e:
        return {"success": False, "error": str(e)}
# ====================== 测试 ======================
if __name__ == "__main__":
    # 测试 1:安全代码
    code1 = "1 + 2 * 3 + PI"
    print("执行结果:", run_js_in_vm2(code1))
    # 测试 2:沙箱禁止的危险代码(会被拦截)
    code2 = "process.exit()"
    print("危险代码执行:", run_js_in_vm2(code2))

3. 运行

python main.py

输出结果

执行结果: {'success': True, 'data': 10.14159}
危险代码执行: {'success': False, 'error': 'ReferenceError: process is not defined'}

✅ 完美实现 Python 调用 vm2 沙箱

方案 B:高性能胶水方案(长连接 RPC)

适合你频繁调用 JS 沙箱的场景(比如批量执行、在线编辑器)。

使用 stdout/stdin 双向通信,Node 保持运行,Python 持续发指令。

1. Node 服务端:rpc_server.js

const { VM } = require('vm2');
const readline = require('readline');

// 创建沙箱
const vm = new VM({
    timeout: 1000,
    allowAsync: true,
    sandbox: { PI: 3.14159 }
});

// 读取 Python 传来的消息
const rl = readline.createInterface({
    input: process.stdin,
    output: process.stdout
});

console.log("VM2 RPC 服务已启动");

rl.on('line', (code) => {
    try {
        const res = vm.run(code);
        console.log(`[RESULT]${JSON.stringify(res)}`);
    } catch (err) {
        console.log(`[ERROR]${err.message}`);
    }
});

2. Python 客户端:rpc_client.py

import subprocess
import threading
import json

class VM2Client:
    def __init__(self):
        # 启动 Node 服务
        self.proc = subprocess.Popen(
            ["node", "rpc_server.js"],
            stdin=subprocess.PIPE,
            stdout=subprocess.PIPE,
            stderr=subprocess.PIPE,
            text=True,
            encoding="utf-8"
        )
        self.response = None

    def _read_output(self):
        while True:
            line = self.proc.stdout.readline()
            if not line:
                break
            self.response = line.strip()

    def run(self, code):
        # 启动监听线程
        threading.Thread(target=self._read_output, daemon=True).start()
        
        # 发送代码
        self.proc.stdin.write(code + "\n")
        self.proc.stdin.flush()
        
        # 等待返回
        while self.response is None:
            pass
        
        res = self.response
        self.response = None
        return res

# ====================== 测试 ======================
if __name__ == "__main__":
    client = VM2Client()

    print(client.run("100 + 200"))
    print(client.run("PI * 2"))
    print(client.run("process"))  # 被沙箱禁止

运行

python rpc_client.py

你可以直接使用的【生产级安全沙箱胶水代码】

我给你整合一个 最实用、最安全、直接复制就能用 的版本:

safe_runner.js

const { NodeVM } = require('vm2');
const code = process.argv[2];

const vm = new NodeVM({
    timeout: 1500,
    eval: false,
    wasm: false,
    console: 'off',
    require: {
        builtin: [],
        external: false,
        deny: ['*']
    }
});

try {
    const result = vm.run(code);
    console.log(JSON.stringify({ ok: 1, data: result }));
} catch (e) {
    console.log(JSON.stringify({ ok: 0, err: e.message }));
}

Python 调用胶水函数

import subprocess
import json
def js_sandbox(js_code: str):
    res = subprocess.run(
        ["node", "safe_runner.js", js_code],
        capture_output=True,
        text=True
    )
    return json.loads(res.stdout)
# 使用
print(js_sandbox("1 + 2 + 3"))

核心总结(你最需要记住的)

到此这篇关于Python 调用 Node.js vm2 沙箱实战教程的文章就介绍到这了,更多相关Python 调用 Node.js沙箱内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

您可能感兴趣的文章:
阅读全文