NPM酷库:vm2,安全的沙箱环境

NPM酷库,天天两分钟,了解一个流行NPM库。git

今天咱们要了解的库是 vm2,则是一个Node.js 官方 vm 库的替代品,主要解决了安全问题。github

不安全的vm

在Node.js官方标准库中有一个vm库,用来在V8虚拟机环境中编译执行JS代码。一般,咱们用vm库来实现一个沙箱,在代码主程序以外执行额外的JS脚本。安全

有时,咱们须要vm虚拟机来执行不受信任的代码,这些代码多是由用户提交的,好比在脉冲云接口文档管理中,容许用户提交Mock.js脚本生成模拟接口数据。而Node.js标准库中的vm是不安全的,用户脚本能够轻易突破沙箱环境,获取主程序的Context!闭包

const vm = require('vm');
vm.runInNewContext('this.constructor.constructor("return process")().exit()');
console.log('Never gets executed.');

上述代码在执行时,程序在第二行就直接退出,vm虚拟机环境中的代码逃逸,得到了主线程的 process 变量,并调用 process.exit(),形成主程序非正常退出。函数

vm不安全的缘由

上文中的代码使用了runInNewContext函数简写,等价于以下代码:ui

const vm = require('vm');

const sandbox = {};
const script = new vm.Script('this.constructor.constructor("return process")().exit()');
const context = vm.createContext(sandbox);

script.runInContext(context);

console.log('Never gets executed.');

从代码中得知,建立vm环境时,首先要初始化一个对象 sendbox,这个对象就是vm中脚本执行时的全局环境Context,vm 脚本中全局 this 指向的就是这个对象。this

而vm中脚本等同于:spa

const sandbox = this; // 获取Context
const ObjectConstructor = this.constructor; // 获取 Object 对象构造函数
const FunctionConstructor = ObjectConstructor.constructor; // 获取 Function 对象构造函数
const myfun = FunctionConstructor('return process'); // 构造一个函数,返回process全局变量
const process = myfun();
process.exit();

从上边脚本中能够看出vm不安全的缘由。vm内部脚本的Context对象是在主程序中定义的,根据JS原型链原理,能够轻松获取主程序中的 Function 对象,用主程序的 Function 对象构造一个函数,那么这个函数运行时,就是在主程序闭包环境中执行的!因此,咱们轻易地获取到了主程序的全局对象 process,最终控制主程序!线程

安全的vm2

vm2就是专门为了解决vm的安全问题而诞生的。code

const { VM } = require('vm2');
const vm = new VM({
    timeout: 1000,
    sandbox: {}
});

vm.run(`process.exit()`); // TypeError: process.exit is not a function

vm2 特性:

  • 运行不受信任的JS脚本
  • 沙箱的终端输出信息彻底可控
  • 沙箱内能够受限地加载modules
  • 能够安全地向沙箱间传递callback
  • 死循环攻击免疫 while (true) {}

vm2 原理:

首先,vm2基于vm,使用官方的vm库构建沙箱环境。而后使用JavaScript的Proxy技术来防止沙箱脚本逃逸。

参考资料

VM2 https://github.com/patriksime...

Proxy https://developer.mozilla.org...

欢迎关注公众号:梁兴臣

梁兴臣

天天了解一个NPM库,一年后成为Node.js高手

相关文章
相关标签/搜索