Heim  >  Artikel  >  Web-Frontend  >  So verwenden Sie die Node.js-Sandbox-Umgebung

So verwenden Sie die Node.js-Sandbox-Umgebung

php中世界最好的语言
php中世界最好的语言Original
2018-05-29 17:36:322107Durchsuche

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

hinzugefügt vm.Module wird hauptsächlich zur Unterstützung von ES6-Modulen verwendet und sein Kontext ist bereits gebunden Wenn es erstellt wird, müssen Sie in Bezug auf vm.Module immer noch das Flag in der Befehlszeile verwenden, um die Unterstützung für

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ähnt

Das VM-Modul ist kein Sicherheitsmechanismus. Verwenden Sie es nicht, um nicht vertrauenswürdigen Code auszuführen

Siehe 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!

Stellungnahme:
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn