Cette fois, je vais vous montrer comment utiliser l'environnement sandbox Node.js et quelles sont les précautions d'utilisation de l'environnement sandbox Node.js. Voici des cas pratiques, voyons. jetez un oeil ensemble Jetez un oeil.
Un cas d'utilisation courant consiste à exécuter le code dans un environnement en bac à sable. Le code en bac à sable utilise un contexte V8 différent, ce qui signifie qu'il a un objet global différent du reste du code.
Regardons d'abord un exemple
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
Le code exécuté dans l'environnement sandbox n'a aucun impact sur le code externe, qu'il s'agisse de la variable b nouvellement déclarée ou de la variable réaffectée a. Notez que la dernière ligne de code sera ajoutée par défaut avec le mot-clé return, il n'est donc pas nécessaire de l'ajouter manuellement. Une fois ajoutée, elle ne sera pas ignorée en silence, mais une erreur sera signalée.
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);
Comme indiqué ci-dessous
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)
En plus de runInNewContext, vm fournit également deux méthodes, runInThisContext et runInContext, qui peuvent toutes deux être utilisées pour exécuter du code runInThisContext ne peut pas spécifier de contexte.
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);
Étant donné que la portée locale n'est pas accessible et que seul l'objet global actuel est accessible, le code ci-dessus signalera une erreur car il ne peut pas trouver localVal
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)
Si nous modifions le code à exécuter S'il est directement assigné, il s'exécutera normalement, mais il provoquera également une pollution globale (variable globale 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 est différent de runInNewContext dans le paramètre de contexte passé. L'objet de contexte transmis par runInContext n'est pas le même. Il est vide et doit être traité par vm.createContext(), sinon une erreur sera signalée. Le paramètre de contexte de runInNewContext est facultatif et n'a pas besoin d'être traité par vm.createContext. Étant donné que runInNewContext et runInContext ont un contexte spécifié, ils ne provoqueront pas de pollution globale comme runInThisContext (aucune variable globale localVar ne sera générée)
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
Lorsque vous avez besoin d'un environnement sandbox pour exécuter plusieurs fragments de script, vous pouvez ceci est obtenu en appelant la méthode runInContext plusieurs fois mais en transmettant la même valeur de retour vm.createContext().
Contrôle du délai d'attente et capture des erreurs
vm fournit un mécanisme de délai d'attente pour le code à exécuter En spécifiant le paramètre timeout, vous pouvez runInThisContext. à titre d'exemple
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)
Les erreurs de code peuvent être détectées via 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'); }
Exécution retardée
vm except En plus d'exécuter le code immédiatement, vous pouvez également le compiler d'abord, puis l'exécuter après un certain temps. Cela nécessite de mentionner vm.Script. En fait, peu importe qu'il s'agisse de runInNewContext, runInThisContext ou runInThisContext, le script est en fait créé derrière lui, comme le montre le message d'erreur précédent. Ensuite, nous utiliserons vm.Script pour réécrire l'exemple au début de cet article. 🎜>
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);
node --experimental-vm-module index.js
vm en tant que bac à sable. environnement Sûr ?
vm est plus sûr que eval car il isole le contexte actuel, mais malgré cela, vous pouvez toujours accéder à l'API JS standard et à l'environnement global NodeJS, donc vm Ce n'est pas sûr. est mentionné dans la documentation officielleLe module vm n'est pas un mécanisme de sécurité. Ne l'utilisez pas pour exécuter du code non fiableVeuillez voir l'exemple ci-dessousAfin d'éviter la situation ci-dessus, le contexte peut être simplifié pour ne contenir que des types de base, comme indiqué ci-dessous
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);
const {VM} = require('vm2'); new VM().run('this.constructor.constructor("return process")().exit()');
const { VM } = require('vm2'); const vm = new VM({ timeout: 1000, sandbox: {}}); vm.run('new Promise(()=>{})');
const { VM } = require('vm2'); const vm = new VM({ timeout: 1000, sandbox: { Promise: function(){}} }); vm.run('Promise = (async function(){})().constructor;new Promise(()=>{});');
Lecture recommandée :
Analyse détaillée du tutoriel d'introduction du mini programme WeChat + étude de casComment utiliser le serveur http dans AngularJS
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!