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

相關文章
相關標籤/搜索