Heim > Artikel > Web-Frontend > So verwenden Sie die Node.js-Sandbox-Umgebung
Dieses Mal zeige ich Ihnen, wie Sie die Node.js-Sandbox-Umgebung verwenden und welche Vorsichtsmaßnahmen für die Verwendung der Node.js-Sandbox-Umgebung gelten. Hier sind praktische Fälle Schauen Sie gemeinsam rein. Schauen Sie mal rein.
Ein häufiger Anwendungsfall ist die Ausführung des Codes in einer Sandbox-Umgebung. Der Sandbox-Code verwendet einen anderen V8-Kontext, was bedeutet, dass er ein anderes globales Objekt als der Rest des Codes hat.
Schauen Sie sich zuerst ein Beispiel an
const vm = require('vm'); let a = 1; var result = vm.runInNewContext('var b = 2; a = 3; a + b;', {a}); console.log(result); // 5 console.log(a); // 1 console.log(typeof b); // undefined
Der in der Sandbox-Umgebung ausgeführte Code hat keinen Einfluss auf den externen Code, unabhängig davon, ob es sich um die neu deklarierte Variable b oder die neu zugewiesene Variable a handelt. Beachten Sie, dass die letzte Codezeile standardmäßig mit dem Schlüsselwort return hinzugefügt wird, sodass keine Notwendigkeit besteht, sie manuell hinzuzufügen. Nach dem Hinzufügen wird sie nicht stillschweigend ignoriert, sondern es wird ein Fehler gemeldet.
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);
ist wie unten gezeigt
evalmachine.<anonymous>:1 var 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)
Zusätzlich zu runInNewContext bietet vm auch zwei Methoden, runInThisContext und runInContext, die beide zum Ausführen von Code verwendet werden können
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);
weil es nicht möglich ist, auf den lokalen Bereich zuzugreifen, kann nur auf das aktuelle globale Objekt zugegriffen werden, daher meldet der obige Code einen Fehler, weil er localVal nicht finden kann
evalmachine.<anonymous>:1 localVar += "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)
Wenn wir den auszuführenden Code auf direkte Zuweisung ändern Es kann normal ausgeführt werden, erzeugt aber auch eine globale Verschmutzung (globale Variable localVar).
const vm = require('vm'); let localVar = 'initial value'; const vmResult = vm.runInThisContext('localVar = "vm";'); console.log('vmResult:', vmResult); // vm console.log('localVar:', localVar); // initial value console.log(global.localVar); // vm
runInContext unterscheidet sich von runInNewContext im übergebenen Kontextparameter. Das von runInContext übergebene Kontextobjekt ist nicht leer und muss übergeben werden über vm.createContext( ), andernfalls wird ein Fehler gemeldet. Der Kontextparameter von runInNewContext ist optional und muss nicht von vm.createContext verarbeitet werden. Da runInNewContext und runInContext einen angegebenen Kontext haben, verursachen sie keine globale Verschmutzung wie runInThisContext (es wird keine globale lokaleVar-Variable generiert).
const vm = require('vm'); let localVar = 'initial value'; const vmResult = vm.runInNewContext('localVar = "vm";'); console.log('vmResult:', vmResult); // vm console.log('localVar:', localVar); // initial value console.log(global.localVar); // undefined
Wenn eine Sandbox-Umgebung zum Ausführen mehrerer Skriptfragmente erforderlich ist, können Sie mehrere Aufrufe verwenden Führen Sie die runInContext-Methode zweimal aus, übergeben Sie jedoch dieselbe vm.createContext()-Rückgabewertimplementierung.
Timeout-Kontrolle und Fehlererfassung
VM bietet einen Timeout-Mechanismus für die Ausführung des Codes, indem Sie den Timeout-Parameter angeben als Beispiel
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)
Sie können Codefehler durch Try Catch abfangen
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'); }
Verzögerte Ausführung
Zusätzlich zum Ausführen von Code sofort, vm auch Sie können es zuerst kompilieren und dann nach einer Weile ausführen. Dazu muss vm.Script erwähnt werden. Unabhängig davon, ob es sich um runInNewContext, runInThisContext oder runInThisContext handelt, wird tatsächlich ein Skript dahinter erstellt. Aus der vorherigen Fehlermeldung geht hervor, dass wir als Nächstes vm.Script verwenden, um das Beispiel am Anfang dieses Artikels neu zu schreiben
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);Außer vm. Script und node wurden in Version 9.6
node --experimental-vm-module index.js
vm als Sandbox-Umgebung Safe zu aktivieren ?
vm ist sicherer als eval, da es den aktuellen Kontext isoliert. Trotzdem können Sie weiterhin auf die Standard-JS-API und die globale NodeJS-Umgebung zugreifen, sodass vm nicht sicher ist wird in der offiziellen Dokumentation erwähntDas VM-Modul ist kein Sicherheitsmechanismus. Verwenden Sie es nicht, um nicht vertrauenswürdigen Code auszuführenSiehe Beispiel unten
const vm = require('vm'); vm.runInNewContext("this.constructor.constructor('return process')().exit()") console.log("The app goes on...") // 永远不会输出Um die obige Situation zu vermeiden, kann der Kontext so vereinfacht werden, dass er nur Basistypen enthält, wie unten gezeigt
let ctx = Object.create(null); ctx.a = 1; // ctx上不能包含引用类型的属性 vm.runInNewContext("this.constructor.constructor('return process')().exit()", ctx);Um dieses Problem der nativen VM anzugehen, hat jemand das VM2-Paket entwickelt. Die oben genannten Probleme können auftreten vermieden werden, aber es kann nicht gesagt werden, dass vm2 unbedingt sicher ist
const {VM} = require('vm2'); new VM().run('this.constructor.constructor("return process")().exit()');Obwohl die Ausführung des obigen Codes kein Problem darstellt, da das Timeout von vm2 für asynchronen Code nicht funktioniert, wird die Ausführung des folgenden Codes niemals beendet. .
const { VM } = require('vm2'); const vm = new VM({ timeout: 1000, sandbox: {}}); vm.run('new Promise(()=>{})');Selbst wenn Sie Promise deaktivieren möchten, indem Sie Promise neu definieren, gibt es immer noch eine Möglichkeit, es zu umgehen.
const { VM } = require('vm2'); const vm = new VM({ timeout: 1000, sandbox: { Promise: function(){}} }); vm.run('Promise = (async function(){})().constructor;new Promise(()=>{});');Ich glaube, Sie haben die Methode gemeistert, nachdem Sie den Fall in diesem Artikel gelesen haben Spannende Dinge, bitte achten Sie auf PHP Weitere verwandte Artikel auf der chinesischen Website! Empfohlene Lektüre:
Detaillierte Analyse des Einführungs-Tutorials + Fallstudie zum WeChat-Miniprogramm
So verwenden Sie den HTTP-Server in AngularJS
Das obige ist der detaillierte Inhalt vonSo verwenden Sie die Node.js-Sandbox-Umgebung. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!