NPM酷库,每天两分钟了解一个流行的NPM库。今天我们要学习的库是vm2,它是Node.js官方vm库的替代品,主要解决安全问题。Unsafevm在Node.js官方标准库中有一个vm库,用于在V8虚拟机环境下编译执行JS代码。通常,我们使用vm库来实现一个沙箱,在主代码程序之外执行额外的JS脚本。有时,我们需要vm虚拟机来执行不可信代码,这些代码可能是用户提交的。例如脉搏云接口文档管理中允许用户提交Mock.js脚本生成模拟接口数据。但是Node.js标准库中的vm并不安全,用户脚本很容易突破沙箱环境,获取主程序的Context!constvm=require('vm');vm.runInNewContext('this.constructor.constructor("返回过程")().exit()');console.log('永远不会被执行。');上面的代码在执行的时候,在第二行程序直接退出,vm虚拟机环境中的代码转义,获取主线程的process变量,调用process.exit(),导致主程序退出不正常的。vm不安全的原因上面的代码使用了runInNewContext函数的简写,相当于下面的代码:constvm=require('vm');const沙盒={};constscript=newvm.Script('this.constructor.constructor("返回过程")().exit()');constcontext=vm.createContext(sandbox);script.runInContext(context);console.log('永远不会被执行。');从代码中了解到,在创建vm环境的时候,首先初始化一个对象sendbox,这个对象就是vm中脚本执行时的全局环境Context,vm脚本中的全局this指向这个对象。而vm中的脚本相当于:constsandbox=this;//获取上下文constObjectConstructor=this.constructor;//获取Object对象的构造函数constFunctionConstructor=ObjectConstructor.constructor;//获取Function对象的构造函数constmyfun=FunctionConstructor('returnprocess');//构造函数并返回进程全局变量constprocess=myfun();process.exit();从上面的脚本中,我们可以看出为什么vm是不安全的。vm内部脚本的Context对象是在主程序中定义的。根据JS原型链原理,主程序中的Function对象很容易获取,用主程序的Function对象构造一个函数。然后,函数运行时,是在主程序的闭包环境中执行的!因此,我们很轻松的拿到了主程序的全局对象进程,最终控制了主程序!safevm2vm2就是专门为解决vm的安全问题而诞生的。const{VM}=require('vm2');constvm=newVM({timeout:1000,sandbox:{}});vm.run(`process.exit()`);//TypeError:process.exitisnotafunctionvm2特性:运行不受信任的JS脚本,沙箱的终端输出信息完全可控,沙箱中可以加载模块,沙箱之间安全传递回调,死循环攻击免疫while(true){}vm2的原理:首先,vm2是基于vm,使用官方的vm库搭建沙箱环境。然后使用JavaScript的Proxy技术来防止沙箱脚本逃逸。参考VM2https://github.com/patriksime...代理https://developer.mozilla.org...欢迎关注公众号:梁星辰每天学一个npm库,做个Node.js一年后掌握
