Maison >interface Web >js tutoriel >Explication détaillée des étapes d'utilisation de l'environnement sandbox Node.js
Cette fois, je vous apporte une explication détaillée des étapes d'utilisation de l'environnement sandbox Node.js, et quelles sont les précautions d'utilisation de l'environnement sandbox Node.js Ici. sont des cas réels, un Levez-vous et jetez un œil.
La documentation officielle de Node mentionne que le module vm de Node peut être utilisé pour exécuter du code dans un environnement sandbox et isoler le contexte du code.
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);Sauf vm.Script, le nœud a été
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...") // 永远不会输出Pour résoudre ce problème de vm natif, quelqu'un a développé avec le package vm2, les problèmes ci-dessus peuvent être évités, mais on ne peut pas dire que vm2 est nécessairement sûr
let ctx = Object.create(null); ctx.a = 1; // ctx上不能包含引用类型的属性 vm.runInNewContext("this.constructor.constructor('return process')().exit()", ctx);Bien qu'il n'y ait aucun problème dans l'exécution du code ci-dessus, car le délai d'attente de vm2 ne fonctionne pas pour le code asynchrone, donc ce qui suit Le code ne se termine jamais.
const {VM} = require('vm2'); new VM().run('this.constructor.constructor("return process")().exit()');Même si vous souhaitez désactiver Promise en redéfinissant Promise, elle peut toujours être contournée
const { VM } = require('vm2'); const vm = new VM({ timeout: 1000, sandbox: {}}); vm.run('new Promise(()=>{})');Je crois que vous maîtrisez la méthode après avoir lu le cas dans cet article, plus Veuillez prêter attention aux autres articles connexes sur le site Web php chinois !
const { VM } = require('vm2'); const vm = new VM({ timeout: 1000, sandbox: { Promise: function(){}} }); vm.run('Promise = (async function(){})().constructor;new Promise(()=>{});');
Lecture recommandée :
Comment gérer l'erreur 404 signalée par l'actualisation de Tomcat lorsque le webpack du projet Vue est empaqueté et déployéGestion
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!