ホームページ  >  記事  >  ウェブフロントエンド  >  Node.jsサンドボックス環境の利用手順を詳しく解説

Node.jsサンドボックス環境の利用手順を詳しく解説

php中世界最好的语言
php中世界最好的语言オリジナル
2018-05-21 14:25:512322ブラウズ

今回は、Node.jsサンドボックス環境を使用する手順について詳しく説明します。Node.jsサンドボックス環境を使用する際の注意事項は何ですか?実際の事例を見てみましょう。

Node の公式ドキュメントには、ノードの vm モジュールを使用してサンドボックス環境でコードを実行し、コードのコンテキストを分離できると記載されています。

一般的な使用例は、サンドボックス環境でコードを実行することです。サンドボックス コードは、コードの残りの部分とは異なるグローバル オブジェクトを持つことを意味します。まず例を見てみましょう。

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
サンドボックス環境で実行されるコードは、新しく宣言された変数 b であっても、再割り当てされた変数 a であっても、外部コードには影響を与えません。 コードの最後の行はデフォルトで return キーワードを使用して追加されるため、手動で追加する必要はありません。追加すると無視されることはありませんが、エラーが報告されます。
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);

以下に示すように

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)

runInNewContext に加えて、vm には runInThisContext と runInContext という 2 つのメソッドも用意されており、どちらもコードの実行に使用できます。 runInThisContext ではコンテキストを指定できません

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);

ローカル スコープにはアクセスできないため、現在のものはグローバルオブジェクトにアクセスできるため、上記のコードは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)

実行するコードを直接代入に変更すると正常に実行されますが、グローバル汚染も引き起こします( global 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 は、渡される context パラメーターにおいて runInNewContext とは異なります。 runInContext によって渡される context オブジェクトは空ではないため、vm.createContext() によって処理する必要があります。それ以外の場合は、エラーが報告されます。 runInNewContext の context パラメータはオプションであり、vm.createContext によって処理される必要はありません。 runInNewContext と runInContext には指定されたコンテキストがあるため、runInThisContext のようなグローバルな汚染を引き起こすことはありません (グローバルな localVar 変数は生成されません)

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

複数のスクリプト フラグメントを実行するためにサンドボックス環境が必要な場合、 runInContext メソッドを複数回呼び出すことができます。同じ vm.createContext() 戻り値の実装を渡します。

タイムアウト制御とエラーキャプチャ

vmは、タイムアウトパラメータを指定することで、例としてInThisContextを実行できますtry catch

const vm = require('vm');
let localVar = 'initial value';
const vmResult = vm.runInThisContext('while(true) { 1 }; localVar = "vm";', { timeout: 1000});
を通じてコードエラーをキャッチできます。

Delay

vm を実行するには、コードをすぐに実行するだけでなく、最初にコードをコンパイルして、しばらくしてから実行することもできます。これには、vm.Script を指定する必要があります。実際、runInNewContext、runInThisContext、または runInThisContext のいずれであっても、実際にはその背後で Script が作成されていることがわかります。次に、vm.Script を使用してこの記事の冒頭の例を書き直します

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)
。バージョン 9.6 では、vm.Script に加えて、vm.Module が に追加され、実行を遅延させることもできます。vm.Module は主に ES6 モジュールをサポートするために使用され、そのコンテキストは作成時にすでにバインドされています。現時点では、vm.Module がまだ必要ですが、コマンド ラインでフラグを使用して

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');
}

vm をサンドボックス環境 としてサポートすることは安全ですか?

vm は現在のコンテキストを分離するため eval より安全ですが、それでも標準の JS API とグローバル NodeJS 環境にアクセスできるため、vm は安全ではありません。これは公式ドキュメントに記載されています。 vm モジュールはセキュリティ機構ではありません。信頼できないコードの実行には使用しないでください以下の例を参照してください

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のこの問題を考慮して、上記の問題を回避できるvm2パッケージを開発された方がいらっしゃいますが、必ずしもvm2が安全とは言えません

const vm = require('vm');
vm.runInNewContext("this.constructor.constructor('return process')().exit()")
console.log("The app goes on...") // 永远不会输出
上記コードの実行には問題ありませんが、 to vm2 タイムアウトは非同期コードには影響しないため、以下のコードは実行を終了しません。

let ctx = Object.create(null);
ctx.a = 1; // ctx上不能包含引用类型的属性
vm.runInNewContext("this.constructor.constructor('return process')().exit()", ctx);
Promise を再定義して Promise を無効にしたい場合でも、バイパスすることができます
const {VM} = require('vm2');
new VM().run('this.constructor.constructor("return process")().exit()');

この記事の事例を読んだ後は、方法を習得したと思います。さらに興味深い情報については、他の関連記事に注目してください。 PHP中国語ウェブサイトです!

推奨読書:

Vue プロジェクト Webpack をパッケージ化してデプロイするときに Tomcat によって報告される 404 エラーに対処するにはどうすればよいですか?

以上がNode.jsサンドボックス環境の利用手順を詳しく解説の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。