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

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

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

不安全的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函数简写,等价于如下代码:

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 指向的就是这个对象。

而vm中脚本等同于:

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的安全问题而诞生的。

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高手


脉冲云-梁兴臣
JS全栈开发,DevOps实施,开发团队效率提升,开发工作体验优化

脉冲云CTO,JS全栈开发,DevOps实施,开发体验优化,开发效率提升

616 声望
191 粉丝
0 条评论
推荐阅读
NPM酷库052:sax,按流解析XML
在NPM酷库051中,我们学习了如何使用xml2js库将XML格式文档字符串解析为JavaScript的对象数据,本期,我们继续学习sax,一个可以以流编程的方式解析XML。

脉冲云_梁兴臣2阅读 3k

从零搭建 Node.js 企业级 Web 服务器(零):静态服务
过去 5 年,我前后在菜鸟网络和蚂蚁金服做开发工作,一方面支撑业务团队开发各类业务系统,另一方面在自己的技术团队做基础技术建设。期间借着 Node.js 的锋芒做了不少 Web 系统,有的至今生气蓬勃、有的早已夭折...

乌柏木150阅读 12.4k评论 10

正则表达式实例
收集在业务中经常使用的正则表达式实例,方便以后进行查找,减少工作量。常用正则表达式实例1. 校验基本日期格式 {代码...} {代码...} 2. 校验密码强度密码的强度必须是包含大小写字母和数字的组合,不能使用特殊...

寒青56阅读 7.9k评论 11

JavaScript有用的代码片段和trick
平时工作过程中可以用到的实用代码集棉。判断对象否为空 {代码...} 浮点数取整 {代码...} 注意:前三种方法只适用于32个位整数,对于负数的处理上和Math.floor是不同的。 {代码...} 生成6位数字验证码 {代码...} ...

jenemy46阅读 6k评论 12

从零搭建 Node.js 企业级 Web 服务器(十五):总结与展望
总结截止到本章 “从零搭建 Node.js 企业级 Web 服务器” 主题共计 16 章内容就更新完毕了,回顾第零章曾写道:搭建一个 Node.js 企业级 Web 服务器并非难事,只是必须做好几个关键事项这几件必须做好的关键事项就...

乌柏木66阅读 6.2k评论 16

再也不学AJAX了!(二)使用AJAX ① XMLHttpRequest
「再也不学 AJAX 了」是一个以 AJAX 为主题的系列文章,希望读者通过阅读本系列文章,能够对 AJAX 技术有更加深入的认识和理解,从此能够再也不用专门学习 AJAX。本篇文章为该系列的第二篇,最近更新于 2023 年 1...

libinfs40阅读 6.3k评论 12

封面图
从零搭建 Node.js 企业级 Web 服务器(一):接口与分层
分层规范从本章起,正式进入企业级 Web 服务器核心内容。通常,一块完整的业务逻辑是由视图层、控制层、服务层、模型层共同定义与实现的,如下图:从上至下,抽象层次逐渐加深。从下至上,业务细节逐渐清晰。视图...

乌柏木44阅读 7.4k评论 6

脉冲云CTO,JS全栈开发,DevOps实施,开发体验优化,开发效率提升

616 声望
191 粉丝
宣传栏