国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 開發 > JS > 正文

淺談Node.js 沙箱環境

2024-05-06 16:44:22
字體:
來源:轉載
供稿:網友

node官方文檔里提到node的vm模塊可以用來做沙箱環境執行代碼,對代碼的上下文環境做隔離。

/A common use case is to run the code in a sandboxed environment. The sandboxed code uses a different V8 Context, meaning that it has a different global object than the rest of the code.

先看一個例子

const vm = require('vm');let a = 1;var result = vm.runInNewContext('var b = 2; a = 3; a + b;', {a});console.log(result);  // 5console.log(a);     // 1console.log(typeof b); // undefined

沙箱環境中執行的代碼對于外部代碼沒有產生任何影響,無論是新聲明的變量b,還是重新賦值的變量a。 注意最后一行的代碼默認會被加上return關鍵字,因此無需手動添加,一旦添加的話不會靜默忽略,而是執行報錯。

const vm = require('vm');let a = 1;var result = vm.runInNewContext('var b = 2; a = 3; return a + b;', {a});console.log(result);console.log(a);console.log(typeof b);

如下所示

evalmachine.<anonymous>:1var b = 2; a = 3; return a + b;         ^^^^^^SyntaxError: Illegal return statement  at new Script (vm.js:74:7)  at createScript (vm.js:246:10)  at Object.runInNewContext (vm.js:291:10)  at Object.<anonymous> (/Users/xiji/workspace/learn/script.js:3:17)  at Module._compile (internal/modules/cjs/loader.js:678:30)  at Object.Module._extensions..js (internal/modules/cjs/loader.js:689:10)  at Module.load (internal/modules/cjs/loader.js:589:32)  at tryModuleLoad (internal/modules/cjs/loader.js:528:12)  at Function.Module._load (internal/modules/cjs/loader.js:520:3)  at Function.Module.runMain (internal/modules/cjs/loader.js:719:10)

除了runInNewContext外,vm還提供了runInThisContext和runInContext兩個方法都可以用來執行代碼 runInThisContext無法指定context

const vm = require('vm');let localVar = 'initial value';?const vmResult = vm.runInThisContext('localVar += "vm";');console.log('vmResult:', vmResult);console.log('localVar:', localVar);console.log(global.localVar);

由于無法訪問本地的作用域,只能訪問到當前的global對象,因此上面的代碼會因為找不到localVal而報錯

evalmachine.<anonymous>:1localVar += "vm";^ReferenceError: localVar is not defined  at evalmachine.<anonymous>:1:1  at Script.runInThisContext (vm.js:91:20)  at Object.runInThisContext (vm.js:298:38)  at Object.<anonymous> (/Users/xiji/workspace/learn/script.js:3:21)  at Module._compile (internal/modules/cjs/loader.js:678:30)  at Object.Module._extensions..js (internal/modules/cjs/loader.js:689:10)  at Module.load (internal/modules/cjs/loader.js:589:32)  at tryModuleLoad (internal/modules/cjs/loader.js:528:12)  at Function.Module._load (internal/modules/cjs/loader.js:520:3)  at Function.Module.runMain (internal/modules/cjs/loader.js:719:10)

如果我們把要執行的代碼改成直接賦值的話就可以正常運行了,但是也產生了全局污染(全局的localVar變量)

const vm = require('vm');let localVar = 'initial value';?const vmResult = vm.runInThisContext('localVar = "vm";');console.log('vmResult:', vmResult);  // vmconsole.log('localVar:', localVar);  // initial valueconsole.log(global.localVar);     // vm

runInContext在傳入context參數上與runInNewContext有所區別 runInContext傳入的context對象不為空而且必須是經vm.createContext()處理過的,否則會報錯。 runInNewContext的context參數是非必須的,而且無需經過vm.createContext處理。 runInNewContext和runInContext因為有指定context,所以不會向runInThisContext那樣產生全局污染(不會產生全局的localVar變量)

const vm = require('vm');let localVar = 'initial value';?const vmResult = vm.runInNewContext('localVar = "vm";');console.log('vmResult:', vmResult);  // vmconsole.log('localVar:', localVar);  // initial valueconsole.log(global.localVar);     // undefined

當需要一個沙箱環境執行多個腳本片段的時候,可以通過多次調用runInContext方法但是傳入同一個vm.createContext()返回值實現。

超時控制及錯誤捕獲

vm針對要執行的代碼提供了超時機制,通過指定timeout參數即可以runInThisContext為例

const vm = require('vm');let localVar = 'initial value';?const vmResult = vm.runInThisContext('while(true) { 1 }; localVar = "vm";', { timeout: 1000});
vm.js:91   return super.runInThisContext(...args);          ^Error: Script execution timed out.  at Script.runInThisContext (vm.js:91:20)  at Object.runInThisContext (vm.js:298:38)  at Object.<anonymous> (/Users/xiji/workspace/learn/script.js:3:21)  at Module._compile (internal/modules/cjs/loader.js:678:30)  at Object.Module._extensions..js (internal/modules/cjs/loader.js:689:10)  at Module.load (internal/modules/cjs/loader.js:589:32)  at tryModuleLoad (internal/modules/cjs/loader.js:528:12)  at Function.Module._load (internal/modules/cjs/loader.js:520:3)  at Function.Module.runMain (internal/modules/cjs/loader.js:719:10)  at startup (internal/bootstrap/node.js:228:19)

可以通過try catch來捕獲代碼錯誤

const vm = require('vm');let localVar = 'initial value';?try {   const vmResult = vm.runInThisContext('while(true) { 1 }; localVar = "vm";', {    timeout: 1000  });} catch(e) {   console.error('executed code timeout');}

延遲執行

vm除了即時執行代碼之外,也可以先編譯然后過一段時間再執行,這就需要提到vm.Script了。其實無論是runInNewContext、runInThisContext還是runInThisContext,背后其實都創建了Script,從之前的報錯信息就可以看出來 接下來我們就用vm.Script來重寫本文開頭的例子

const vm = require('vm');let a = 1;var script = new vm.Script('var b = 2; a = 3; a + b;');setTimeout(() => {   let result = script.runInNewContext({a});   console.log(result);   // 5   console.log(a);     // 1   console.log(typeof b);  // undefined}, 300);

除了vm.Script,node在9.6版本中新增了vm.Module也可以做到延遲執行,vm.Module主要用來支持ES6 module,而且它的context在創建的時候就已經綁定好了,關于vm.Module目前還需要在命令行使用flag來啟用支持

node --experimental-vm-module index.js

vm作為沙箱環境安全嗎?

vm相對于eval來說更安全一些,因為它隔離了當前的上下文環境了,但是盡管如此依然可以訪問標準的JS API和全局的NodeJS環境,因此vm并不安全,這個在官方文檔里就提到了

The vm module is not a security mechanism. Do not use it to run untrusted code

請看下面的例子

const vm = require('vm');vm.runInNewContext("this.constructor.constructor('return process')().exit()")console.log("The app goes on...") // 永遠不會輸出

為了避免上面這種情況,可以將上下文簡化成只包含基本類型,如下所示

let ctx = Object.create(null);ctx.a = 1; // ctx上不能包含引用類型的屬性vm.runInNewContext("this.constructor.constructor('return process')().exit()", ctx);

針對原生vm存在的這個問題,有人開發了vm2包,可以避免上述問題,但是也不能說vm2就一定是安全的

const {VM} = require('vm2');new VM().run('this.constructor.constructor("return process")().exit()');

雖然執行上述代碼沒有問題,但是由于vm2的timeout對于異步代碼不起作用,所以下面的代碼永遠不會執行結束。

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

即使希望通過重新定義Promise的方式來禁用Promise的話,還是一個可以繞過的

const { VM } = require('vm2');const vm = new VM({  timeout: 1000, sandbox: { Promise: function(){}}});vm.run('Promise = (async function(){})().constructor;new Promise(()=>{});');

以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持VeVb武林網。


注:相關教程知識閱讀請移步到JavaScript/Ajax教程頻道。
發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 闽侯县| 金华市| 怀柔区| 黄梅县| 贺兰县| 青铜峡市| 广宁县| 巴彦县| 北宁市| 毕节市| 涟水县| 武陟县| 成武县| 佳木斯市| 桑植县| 吴忠市| 宽城| 永靖县| 永德县| 宁明县| 鹤壁市| 鹰潭市| 温州市| 嘉荫县| 石景山区| 蓝山县| 柳林县| 什邡市| 蒙城县| 会同县| 大新县| 鄂州市| 金昌市| 马边| 类乌齐县| 东山县| 盐池县| 娄烦县| 周口市| 潞城市| 遂宁市|