Maison >interface Web >js tutoriel >Explication détaillée des étapes d'utilisation de l'environnement sandbox Node.js

Explication détaillée des étapes d'utilisation de l'environnement sandbox Node.js

php中世界最好的语言
php中世界最好的语言original
2018-05-21 14:25:512430parcourir

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é

ajouté dans la version 9.6. vm.Module peut également être retardé dans son exécution. vm.Module est principalement utilisé pour prendre en charge les modules ES6, et son exécution. le contexte est déjà lié lors de sa création. D'accord, concernant vm.Module, vous devez toujours utiliser l'indicateur sur la ligne de commande pour activer la prise en charge de

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 officielle

Le module vm n'est pas un mécanisme de sécurité. Ne l'utilisez pas pour exécuter du code non fiable

Veuillez voir l'exemple ci-dessous

Afin 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

Explication détaillée des étapes pour implémenter le menu de routage d'autorisations dynamique avec vue addRoutes

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!

Déclaration:
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn