
Node.js向けの隔離されたJavaScriptサンドボックス。Proxyベースのインターセプトにより、組み込みモジュールやホストリソースへのアクセスを制限しながら、信頼できないコードを実行します。
vm2 は、ホワイトリストに登録された Node の組み込みモジュールを使用して信頼できないコードを実行できるサンドボックスです。
npm install vm2
## クイック例```js
import { VM } from 'vm2';
const vm = new VM();
vm.run(`process.exit()`); // TypeError: process.exit is not a function
The -p flag is used to specify the port number. The -h flag is used to display the help menu. The -v flag is used to enable verbose output. The -t flag is used to specify the target IP address or hostname. The -f flag is used to specify the file containing the list of targets. The -o flag is used to specify the output file for the results. The -c flag is used to specify the number of concurrent threads. The -d flag is used to specify the delay between requests. The -r flag is used to specify the number of retries. The -s flag is used to specify the timeout value. The -u flag is used to specify the user agent string. The -x flag is used to specify the proxy server. The -k flag is used to specify the cookie string. The -a flag is used to specify the authentication credentials. The -e flag is used to specify the encoding type. The -q flag is used to enable quiet mode. The -i flag is used to specify the input file. The -l flag is used to specify the log file. The -m flag is used to specify the maximum number of results. The -n flag is used to specify the minimum number of results. The -b flag is used to specify the base URL. The -w flag is used to specify the wordlist file. The -z flag is used to specify the compression type. The -y flag is used to specify the proxy type. The -g flag is used to specify the grep pattern. The -j flag is used to specify the JSON output format. The -x flag is used to specify the XML output format. The -c flag is used to specify the CSV output format. The -h flag is used to display the help menu. The -v flag is used to enable verbose output. The -t flag is used to specify the target IP address or hostname. The -f flag is used to specify the file containing the list of targets. The -o flag is used to specify the output file for the results. The -c flag is used to specify the number of concurrent threads. The -d flag is used to specify the delay between requests. The -r flag is used to specify the number of retries. The -s flag is used to specify the timeout value. The -u flag is used to specify the user agent string. The -x flag is used to specify the proxy server. The -k flag is used to specify the cookie string. The -a flag is used to specify the authentication credentials. The -e flag is used to specify the encoding type. The -q flag is used to enable quiet mode. The -i flag is used to specify the input file. The -l flag is used to specify the log file. The -m flag is used to specify the maximum number of results. The -n flag is used to specify the minimum number of results. The -b flag is used to specify the base URL. The -w flag is used to specify the wordlist file. The -z flag is used to specify the compression type. The -y flag is used to specify the proxy type. The -g flag is used to specify the grep pattern. The -j flag is used to specify the JSON output format. The -x flag is used to specify the XML output format. The -c flag is used to specify the CSV output format. The -h flag is used to display the help menu. The -v flag is used to enable verbose output. The -t flag is used to specify the target IP address or hostname. The -f flag is used to specify the file containing the list of targets. The -o flag is used to specify the output file for the results. The -c flag is used to specify the number of concurrent threads. The -d flag is used to specify the delay between requests. The -r flag is used to specify the number of retries. The -s flag is used to specify the timeout value. The -u flag is used to specify the user agent string. The -x flag is used to specify the proxy server. The -k flag is used to specify the cookie string. The -a flag is used to specify the authentication credentials. The -e flag is used to specify the encoding type. The -q flag is used to enable quiet mode. The -i flag is used to specify the input file. The -l flag is used to specify the log file. The -m flag is used to specify the maximum number of results. The -n flag is used to specify the minimum number of results. The -b flag is used to specify the base URL. The -w flag is used to specify the wordlist file. The -z flag is used to specify the compression type. The -y flag is used to specify the proxy type. The -g flag is used to specify the grep pattern. The -j flag is used to specify the JSON output format. The -x flag is used to specify the XML output format. The -c flag is used to specify the CSV output format. The -h flag is used to display the help menu. The -v flag is used to enable verbose output. The -t flag is used to specify the target IP address or hostname. The -f flag is used to specify the file containing the list of targets. The -o flag is used to specify the output file for the results. The -c flag is used to specify the number of concurrent threads. The -d flag is used to specify the delay between requests. The -r flag is used to specify the number of retries. The -s flag is used to specify the timeout value. The -u flag is used to specify the user agent string. The -x flag is used to specify the proxy server. The -k flag is used to specify the cookie string. The -a flag is used to specify the authentication credentials. The -e flag is used to specify the encoding type. The -q flag is used to enable quiet mode. The -i flag is used to specify the input file. The -l flag is used to specify the log file. The -m flag is used to specify the maximum number of results. The -n flag is used to specify the minimum number of results. The -b flag is used to specify the base URL. The -w flag is used to specify the wordlist file. The -z flag is used to specify the compression type. The -y flag is used to specify the proxy type. The -g flag is used to specify the grep pattern. The -j flag is used to specify the JSON output format. The -x flag is used to specify the XML output format. The -c flag is used to specify the CSV output format. The -h flag is used to display the help menu. The -v flag is used to enable verbose output. The -t flag is used to specify the target IP address or hostname. The -f flag is used to specify the file containing the list of targets. The -o flag is used to specify the output file for the results. The -c flag is used to specify the number of concurrent threads. The -d flag is used to specify the delay between requests. The -r flag is used to specify the number of retries. The -s flag is used to specify the timeout value. The -u flag is used to specify the user agent string. The -x flag is used to specify the proxy server. The -k flag is used to specify the cookie string. The -a flag is used to specify the authentication credentials. The -e flag is used to specify the encoding type. The -q flag is used to enable quiet mode. The -i flag is used to specify the input file. The -l flag is used to specify the log file. The -m flag is used to specify the maximum number of results. The -n flag is used to specify the minimum number of results. The -b flag is used to specify the base URL. The -w flag is used to specify the wordlist file. The -z flag is used to specify the compression type. The -y flag is used to specify the proxy type. The -g flag is used to specify the grep pattern. The -j flag is used to specify the JSON output format. The -x flag is used to specify the XML output format. The -c flag is used to specify the CSV output format. The -h flag is used to display the help menu. The -v flag is used to enable verbose output. The -t flag is used to specify the target IP address or hostname. The -f flag is used to specify the file containing the list of targets. The -o flag is used to specify the output file for the results. The -c flag is used to specify the number of concurrent threads. The -d flag is used to specify the delay between requests. The -r flag is used to specify the number of retries. The -s flag is used to specify the timeout value. The -u flag is used to specify the user agent string. The -x flag is used to specify the proxy server. The -k flag is used to specify the cookie string. The -a flag is used to specify the authentication credentials. The -e flag is used to specify the encoding type. The -q flag is used to enable quiet mode. The -i flag is used to specify the input file. The -l flag is used to specify the log file. The -m flag is used to specify the maximum number of results. The -n flag is used to specify the minimum number of results. The -b flag is used to specify the base URL. The -w flag is used to specify the wordlist file. The -z flag is used to specify the compression type. The -y flag is used to specify the proxy type. The -g flag is used to specify the grep pattern. The -j flag is used to specify the JSON output format. The -x flag is used to specify the XML output format. The -c flag is used to specify the CSV output format. The -h flag is used to display the help menu. The -v flag is used to enable verbose output. The -t flag is used to specify the target IP address or hostname. The -f flag is used to specify the file containing the list of targets. The -o flag is used to specify the output file for the results. The -c flag is used to specify the number of concurrent threads. The -d flag is used to specify the delay between requests. The -r flag is used to specify the number of retries. The -s flag is used to specify the timeout value. The -u flag is used to specify the user agent string. The -x flag is used to specify the proxy server. The -k flag is used to specify the cookie string. The -a flag is used to specify the authentication credentials. The -e flag is used to specify the encoding type. The -q flag is used to enable quiet mode. The -i flag is used to specify the input file. The -l flag is used to specify the log file. The -m flag is used to specify the maximum number of results. The -n flag is used to specify the minimum number of results. The -b flag is used to specify the base URL. The -w flag is used to specify the wordlist file. The -z flag is used to specify the compression type. The -y flag is used to specify the proxy type. The -g flag is used to specify the grep pattern. The -j flag is used to specify the JSON output format. The -x flag is used to specify the XML output format. The -c flag is used to specify the CSV output format. The -h flag is used to display the help menu. The -v flag is used to enable verbose output. The -t flag is used to specify the target IP address or hostname. The -f flag is used to specify the file containing the list of targets. The -o flag is used to specify the output file for the results. The -c flag is used to specify the number of concurrent threads. The -d flag is used to specify the delay between requests. The -r flag is used to specify the number of retries. The -s flag is used to specify the timeout value. The -u flag is used to specify the user agent string. The -x flag is used to specify the proxy server. The -k flag is used to specify the cookie string. The -a flag is used to specify the authentication credentials. The -e flag is used to specify the encoding type. The -q flag is used to enable quiet mode. The -i flag is used to specify the input file. The -l flag is used to specify the log file. The -m flag is used to specify the maximum number of results. The -n flag is used to specify the minimum number of results. The -b flag is used to specify the base URL. The -w flag is used to specify the wordlist file. The -z flag is used to specify the compression type. The -y flag is used to specify the proxy type. The -g flag is used to specify the grep pattern. The -j flag is used to specify the JSON output format. The -x flag is used to specify the XML output format. The -c flag is used to specify the CSV output format. The -h flag is used to display the help menu. The -v flag is used to enable verbose output. The -t flag is used to specify the target IP address or hostname. The -f flag is used to specify the file containing the list of targets. The -o flag is used to specify the output file for the results. The -c flag is used to specify the number of concurrent threads. The -d flag is used to specify the delay between requests. The -r flag is used to specify the number of retries. The -s flag is used to specify the timeout value. The -u flag is used to specify the user agent string. The -x flag is used to specify the proxy server. The -k flag is used to specify the cookie string. The -a flag is used to specify the authentication credentials. The -e flag is used to specify the encoding type. The -q flag is used to enable quiet mode. The -i flag is used to specify the input file. The -l flag is used to specify the log file. The -m flag is used to specify the maximum number of results. The -n flag is used to specify the minimum number of results. The -b flag is used to specify the base URL. The -w flag is used to specify the wordlist file. The -z flag is used to specify the compression type. The -y flag is used to specify the proxy type. The -g flag is used to specify the grep pattern. The -j flag is used to specify the JSON output format. The -x flag is used to specify the XML output format. The -c flag is used to specify the CSV output format. The -h flag is used to display the help menu. The -v flag is used to enable verbose output. The -t flag is used to specify the target IP address or hostname. The -f flag is used to specify the file containing the list of targets. The -o flag is used to specify the output file for the results. The -c flag is used to specify the number of concurrent threads. The -d flag is used to specify the delay between requests. The -r flag is used to specify the number of retries. The -s flag is used to specify the timeout value. The -u flag is used to specify the user agent string. The -x flag is used to specify the proxy server. The -k flag is used to specify the cookie string. The -a flag is used to specify the authentication credentials. The -e flag is used to specify the encoding type. The -q flag is used to enable quiet mode. The -i flag is used to specify the input file. The -l flag is used to specify the log file. The -m flag is used to specify the maximum number of results. The -n flag is used to specify the minimum number of results. The -b flag is used to specify the base URL. The -w flag is used to specify the wordlist file. The -z flag is used to specify the compression type. The -y flag is used to specify the proxy type. The -g flag is used to specify the grep pattern. The -j flag is used to specify the JSON output format. The -x flag is used to specify the XML output format. The -c flag is used to specify the CSV output format. The -h flag is used to display the help menu. The -v flag is used to enable verbose output. The -t flag is used to specify the target IP address or hostname. The -f flag is used to specify the file containing the list of targets. The -o flag is used to specify the output file for the results. The -c flag is used to specify the number of concurrent threads. The -d flag is used to specify the delay between requests. The -r flag is used to specify the number of retries. The -s flag is used to specify the timeout value. The -u flag is used to specify the user agent string. The -x flag is used to specify the proxy server. The -k flag is used to specify the cookie string. The -a flag is used to specify the authentication credentials. The -e flag is used to specify the encoding type. The -q flag is used to enable quiet mode. The -i flag is used to specify the input file. The -l flag is used to specify the log file. The -m flag is used to specify the maximum number of results. The -n flag is used to specify the minimum number of results. The -b flag is used to specify the base URL. The -w flag is used to specify the wordlist file. The -z flag is used to specify the compression type. The -y flag is used to specify the proxy type. The -g flag is used to specify the grep pattern. The -j flag is used to specify the JSON output format. The -x flag is used to specify the XML output format. The -c flag is used to specify the CSV output format. The -h flag is used to display the help menu. The -v flag is used to enable verbose output. The -t flag is used to specify the target IP address or hostname. The -f flag is used to specify the file containing the list of targets. The -o flag is used to specify the output file for the results. The -c flag is used to specify the number of concurrent threads. The -d flag is used to specify the delay between requests. The -r flag is used to specify the number of retries. The -s flag is used to specify the timeout value. The -u flag is used to specify the user agent string. The -x flag is used to specify the proxy server. The -k flag is used to specify the cookie string. The -a flag is used to specify the authentication credentials. The -e flag is used to specify the encoding type. The -q flag is used to enable quiet mode. The -i flag is used to specify the input file. The -l flag is used to specify the log file. The -m flag is used to specify the maximum number of results. The -n flag is used to specify the minimum number of results. The -b flag is used to specify the base URL. The -w flag is used to specify the wordlist file. The -z flag is used to specify the compression type. The -y flag is used to specify the proxy type. The -g flag is used to specify the grep pattern. The -j flag is used to specify the JSON output format. The -x flag is used to specify the XML output format. The -c flag is used to specify the CSV output format. The -h flag is used to display the help menu. The -v flag is used to enable verbose output. The -t flag is used to specify the target IP address or hostname. The -f flag is used to specify the file containing the list of targets. The -o flag is used to specify the output file for the results. The -c flag is used to specify the number of concurrent threads. The -d flag is used to specify the delay between requests. The -r flag is used to specify the number of retries. The -s flag is used to specify the timeout value. The -u flag is used to specify the user agent string. The -x flag is used to specify the proxy server. The -k flag is used to specify the cookie string. The -a flag is used to specify the authentication credentials. The -e flag is used to specify the encoding type. The -q flag is used to enable quiet mode. The -i flag is used to specify the input file. The -l flag is used to specify the log file. The -m flag is used to specify the maximum number of results. The -n flag is used to specify the minimum number of results. The -b flag is used to specify the base URL. The -w flag is used to specify the wordlist file. The -z flag is used to specify the compression type. The -y flag is used to specify the proxy type. The -g flag is used to specify the grep pattern. The -j flag is used to specify the JSON output format. The -x flag is used to specify the XML output format. The -c flag is used to specify the CSV output format. The -h flag is used to display the help menu. The -v flag is used to enable verbose output. The -t flag is used to specify the target IP address or hostname. The -f flag is used to specify the file containing the list of targets. The -o flag is used to specify the output file for the results. The -c flag is used to specify the number of concurrent threads. The -d flag is used to specify the delay between requests. The -r flag is used to specify the number of retries. The -s flag is used to specify the timeout value. The -u flag is used to specify the user agent string. The -x flag is used to specify the proxy server. The -k flag is used to specify the cookie string. The -a flag is used to specify the authentication credentials. The -e flag is used to specify the encoding type. The -q flag is used to enable quiet mode. The -i flag is used to specify the input file. The -l flag is used to specify the log file. The -m flag is used to specify the maximum number of results. The -n flag is used to specify the minimum number of results. The -b flag is used to specify the base URL. The -w flag is used to specify the wordlist file. The -z flag is used to specify the compression type. The -y flag is used to specify the proxy type. The -g flag is used to specify the grep pattern. The -j flag is used to specify the JSON output format. The -x flag is used to specify the XML output format. The -c flag is used to specify the CSV output format. The -h flag is used to display the help menu. The -v flag is used to enable verbose output. The -t flag is used to specify the target IP address or hostname. The -f flag is used to specify the file containing the list of targets. The -o flag is used to specify the output file for the results. The -c flag is used to specify the number of concurrent threads. The -d flag is used to specify the delay between requests. The -r flag is used to specify the number of retries. The -s flag is used to specify the timeout value. The -u flag is used to specify the user agent string. The -x flag is used to specify the proxy server. The -k flag is used to specify the cookie string. The -a flag is used to specify the authentication credentials. The -e flag is used to specify the encoding type. The -q flag is used to enable quiet mode. The -i flag is used to specify the input file. The -l flag is used to specify the log file. The -m flag is used to specify the maximum number of results. The -n flag is used to specify the minimum number of results. The -b flag is used to specify the base URL. The -w flag is used to specify the wordlist file. The -z flag is used to specify the compression type. The -y flag is used to specify the proxy type. The -g flag is used to specify the grep pattern. The -j flag is used to specify the JSON output format. The -x flag is used to specify the XML output format. The -c flag is used to specify the CSV output format. The -h flag is used to display the help menu. The -v flag is used to enable verbose output. The -t flag is used to specify the target IP address or hostname. The -f flag is used to specify the file containing the list of targets. The -o flag is used to specify the output file for the results. The -c flag is used to specify the number of concurrent threads. The -d flag is used to specify the delay between requests. The -r flag is used to specify the number of retries. The -s flag is used to specify the timeout value. The -u flag is used to specify the user agent string. The -x flag is used to specify the proxy server. The -k flag is used to specify the cookie string. The -a flag is used to specify the authentication credentials. The -e flag is used to specify the encoding type. The -q flag is used to enable quiet mode. The -i flag is used to specify the input file. The -l flag is used to specify the log file. The -m flag is used to specify the maximum number of results. The -n flag is used to specify the minimum number of results. The -b flag is used to specify the base URL. The -w flag is used to specify the wordlist file. The -z flag is used to specify the compression type. The -y flag is used to specify the proxy type. The -g flag is used to specify the grep pattern. The -j flag is used to specify the JSON output format. The -x flag is used to specify the XML output format. The -c flag is used to specify the CSV output format. The -h flag is used to display the help menu. The -v flag is used to enable verbose output. The -t flag is used to specify the target IP address or hostname. The -f flag is used to specify the file containing the list of targets. The -o flag is used to specify the output file for the results. The -c flag is used to specify the number of concurrent threads. The -d flag is used to specify the delay between requests. The -r flag is used to specify the number of retries. The -s flag is used to specify the timeout value. The -u flag is used to specify the user agent string. The -x flag is used to specify the proxy server. The -k flag is used to specify the cookie string. The -a flag is used to specify the authentication credentials. The -e flag is used to specify the encoding type. The -q flag is used to enable quiet mode. The -i flag is used to specify the input file. The -l flag is used to specify the log file. The -m flag is used to specify the maximum number of results. The -n flag is used to specify the minimum number of results. The -b flag is used to specify the base URL. The -w flag is used to specify the wordlist file. The -z flag is used to specify the compression type. The -y flag is used to specify the proxy type. The -g flag is used to specify the grep pattern. The -j flag is used to specify the JSON output format. The -x flag is used to specify the XML output format. The -c flag is used to specify the CSV output format. The -h flag is used to display the help menu. The -v flag is used to enable verbose output. The -t flag is used to specify the target IP address or hostname. The -f flag is used to specify the file containing the list of targets. The -o flag is used to specify the output file for the results. The -c flag is used to specify the number of concurrent threads. The -d flag is used to specify the delay between requests. The -r flag is used to specify the number of retries. The -s flag is used to specify the timeout value. The -u flag is used to specify the user agent string. The -x flag is used to specify the proxy server. The -k flag is used to specify the cookie string. The -a flag is used to specify the authentication credentials. The -e flag is used to specify the encoding type. The -q flag is used to enable quiet mode. The -i flag is used to specify the input file. The -l flag is used to specify the log file. The -m flag is used to specify the maximum number of results. The -n flag is used to specify the minimum number of results. The -b flag is used to specify the base URL. The -w flag is used to specify the wordlist file. The -z flag is used to specify the compression type. The -y flag is used to specify the proxy type. The -g flag is used to specify the grep pattern. The -j flag is used to specify the JSON output format. The -x flag is used to specify the XML output format. The -c flag is used to specify the CSV output format. The -h flag is used to display the help menu. The -v flag is used to enable verbose output. The -t flag is used to specify the target IP address or hostname. The -f flag is used to specify the file containing the list of targets. The -o flag is used to specify the output file for the results. The -c flag is used to specify the number of concurrent threads. The -d flag is used to specify the delay between requests. The -r flag is used to specify the number of retries. The -s flag is used to specify the timeout value. The -u flag is used to specify the user agent string. The -x flag is used to specify the proxy server. The -k flag is used to specify the cookie string. The -a flag is used to specify the authentication credentials. The -e flag is used to specify the encoding type. The -q flag is used to enable quiet mode. The -i flag is used to specify the input file. The -l flag is used to specify the log file. The -m flag is used to specify the maximum number of results. The -n flag is used to specify the minimum number of results. The -b flag is used to specify the base URL. The -w flag is used to specify the wordlist file. The -z flag is used to specify the compression type. The -y flag is used to specify the proxy type. The -g flag is used to specify the grep pattern. The -j flag is used to specify the JSON output format. The -x flag is used to specify the XML output format. The -c flag is used to specify the CSV output format. The -h flag is used to display the help menu. The -v flag is used to enable verbose output. The -t flag is used to specify the target IP address or hostname. The -f flag is used to specify the file containing the list of targets. The -o flag is used to specify the output file for the results. The -c flag is used to specify the number of concurrent threads. The -d flag is used to specify the delay between requests. The -r flag is used to specify the number of retries. The -s flag is used to specify the timeout value. The -u flag is used to specify the user agent string. The -x flag is used to specify the proxy server. The -k flag is used to specify the cookie string. The -a flag is used to specify the authentication credentials. The -e flag is used to specify the encoding type. The -q flag is used to enable quiet mode. The -i flag is used to specify the input file. The -l flag is used to specify the log file. The -m flag is used to specify the maximum number of results. The -n flag is used to specify the minimum number of results. The -b flag is used to specify the base URL. The -w flag is used to specify the wordlist file. The -z flag is used to specify the compression type. The -y flag is used to specify the proxy type. The -g flag is used to specify the grep pattern. The -j flag is used to specify the JSON output format. The -x flag is used to specify the XML output format. The -c flag is used to specify the CSV output format. The -h flag is used to display the help menu. The -v flag is used to enable verbose output. The -t flag is used to specify the target IP address or hostname. The -f flag is used to specify the file containing the list of targets. The -o flag is used to specify the output file for the results. The -c flag is used to specify the number of concurrent threads. The -d flag is used to specify the delay between requests. The -r flag is used to specify the number of retries. The -s flag is used to specify the timeout value. The -u flag is used to specify the user agent string. The ````js
import { NodeVM } from 'vm2';
const vm = new NodeVM({ require: { external: true, root: './', }, });
vm.run(
var request = require('request'); request('http://www.google.com', function (error, response, body) { console.error(error); if (!error && response.statusCode == 200) { console.log(body); // Show the HTML for the Google homepage. } });,
'vm.js',
);
## 重要なセキュリティ免責事項
**vm2を使用する前に、その仕組みと制限事項を理解しておく必要があります。**
vm2は、信頼できないJavaScriptコードを、アプリケーションと同じNode.jsプロセス内でサンドボックス化しようと試みます。これは、サンドボックスとホスト環境の間のすべてのやり取りを傍受して仲介する[プロキシ](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Proxy)の複雑なネットワークを通じて実現されます。
### 根本的な課題
JavaScriptは非常に動的な言語です。オブジェクトはプロトタイプチェーンを通じてアクセスでき、コンストラクタはエラーオブジェクト経由で到達でき、シンボルはプロトコルフックを提供し、非同期実行はタイミングの窓を作り出します。JavaScriptでオブジェクトから別のオブジェクトへ移動する方法が非常に多いため、堅牢なプロセス内サンドボックスを構築することは極めて困難です。
**私たちはこの現実について正直です:** 最善を尽くしても、研究者やセキュリティ専門家はvm2サンドボックスを脱出する新しい方法を継続的に発見しています。報告された脆弱性は積極的にパッチを適用していますが、プロセス内サンドボックス化のいたちごっこの性質上、以下のことが言えます:
1. **新しいバイパスが将来発見される可能性が高いです。** 既知の脆弱性については、[セキュリティアドバイザリ](https://github.com/patriksimek/vm2/security/advisories)を確認してください。
2. **最新のセキュリティ修正の恩恵を受けるには、vm2を最新に保つ必要があります。** セキュリティアドバイザリを購読し、迅速に更新してください。
3. **vm2を唯一の防御線にすべきではありません。** 信頼できないコードを実行する場合、多層防御が不可欠です。
### より堅牢な代替案
より強力な分離保証が必要な場合は、**真のプロセスまたはハードウェアレベルの分離**を提供する以下の代替案を検討してください:
| ソリューション | アプローチ | パフォーマンス | トレードオフ |
|----------|----------|-------------|------------|
| **[isolated-vm](https://github.com/laverdet/isolated-vm)** | 個別のV8アイソレート(異なるV8ヒープ) | 高速 | メンテナンスモード; 手動でのV8更新が必要 |
| **別プロセス / Worker** | 権限が制限された`child_process`またはWorkerスレッド | 中程度 | IPCオーバーヘッドが高い; データをシリアライズする必要がある |
| **コンテナ / VM** | Docker、gVisor、Firecracker | 低速 | 起動オーバーヘッド; リソース消費が大きい |
| **マネージドサービス** | クラウドベースのコード実行(例: AWS Lambda、Cloudflare Workers) | 変動あり | ネットワーク遅延; 外部依存 |
### vm2が依然として適切な場合
vm2は以下の場合に適しています:
- ホストオブジェクトとの緊密な統合と高速な同期通信が必要な場合
- 信頼できないコードが比較的信頼できるソースからのものである場合(例: 内部ツール、審査済みの作成者によるプラグインシステム)
- vm2を他のセキュリティレイヤー(ネットワーク分離、ファイルシステム制限、リソース制限)と組み合わせる場合
- リスクを受け入れ、セキュリティ更新を積極的に監視する場合
**完全に信頼できないソース(例: 任意のユーザー送信)からのコードを実行する場合は、より強力な分離保証を備えたソリューションの使用を強くお勧めします。**
## ランタイム
| ランタイム | ステータス |
|---------|--------|
| Node.js | サポート対象。サンドボックスはセキュリティ境界です。 |
| Bun | **実験的。** 部分的な機能互換性 — **セキュリティ境界ではありません。** |
Bunには2つの別々の制限が適用され、どちらも他方を意味するものではありません。
**セキュリティ境界ではありません。** vm2の脅威モデル、[`docs/ATTACKS.md`](https://github.com/patriksimek/vm2/blob/main/docs/ATTACKS.md)の攻撃カタログ、および`test/ghsa/`内のすべてのリグレッションテストは、V8の内部構造に由来しています。Bunが使用するJavaScriptCoreには独自の同等物がありますが、vm2のブリッジに対して監査されたものはありません。Bunでテストスイートが合格することは互換性を示すものであり、そこでサンドボックスが機能することを示すものではありません。**信頼できないコードを分離するためにBunでvm2を使用しないでください。**
**互換性は部分的なものであり、同等ではありません。** Bunでのグリーンな実行は、実際にそこで実行されるテストのみを対象としています。`test/bun-skips.js`には、何が除外され、その理由が記載されています。既知の動作上のギャップには以下が含まれます:
- `Buffer.from(arrayLike)` はゼロ長バッファを返します
- `VMScript`の`filename` / `lineOffset` / `columnOffset`メタデータは、JSCのCallSiteオブジェクトにメソッドがないため、監視できません
- 非設定可能なアクセサを持つ凍結されたホストオブジェクトに対する`Object.freeze`は、V8では発生しないプロキシ不変条件の`TypeError`をスローします
- サンドボックス境界を越える一部の`Buffer`操作は大幅に遅くなります — 64 MBの`allocUnsafe`はNodeの1.7に対して400秒以上かかり、ハングと読み取れるほど遅いです
Bunサポートは、信頼できるコードに対するベストエフォートの互換性として扱い、特定の動作に依存する前にスキップリストを確認してください。
## 機能
- 信頼できないコードを、あなたのコードと同じプロセス内で安全に実行します
- サンドボックスのコンソール出力を完全に制御できます
- サンドボックスはプロセスのメソッドへのアクセスが制限されています
- サンドボックスからモジュール(組み込みおよび外部)をrequireすることが可能です
- 特定の(またはすべての)組み込みモジュールへのアクセスを制限できます
- サンドボックス間でメソッドを安全に呼び出し、データとコールバックを交換できます
- 既知の脱出方法に対するパッチで積極的にメンテナンスされています([セキュリティ免責事項](#important-security-disclaimer)を参照)
- トランスパイラのサポート
## 仕組み
- 内部のVMモジュールを使用してセキュアコンテキストを作成します。
- [プロキシ](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Proxy)を使用してサンドボックスからの脱出を防ぎます。
- 組み込みのrequireをオーバーライドしてモジュールへのアクセスを制御します。
vm2の内部構造の詳細については、[docs/ATTACKS.md](https://github.com/patriksimek/vm2/blob/main/docs/ATTACKS.md)を参照してください。
## Nodeのvmとvm2の違いは何ですか?
自分で試してみてください:```js
import { runInNewContext } from "node:vm";
runInNewContext('this.constructor.constructor("return process")().exit()');
console.log('Never gets executed.');
The --no-verify flag is used to skip the verification of the certificate. This is useful when you are using a self-signed certificate or a certificate that is not trusted by the system. However, this flag should be used with caution as it can expose you to man-in-the-middle attacks.```js
import { VM } from 'vm2';
new VM().run('this.constructor.constructor("return process")().exit()'); // Throws ReferenceError: process is not defined
## ドキュメント
- [VM](#vm)
- [NodeVM](#nodevm)
- [VMScript](#vmscript)
- [エラー処理](#error-handling)
- [サンドボックス化されたコードのデバッグ](#debugging-a-sandboxed-code)
- [読み取り専用オブジェクト](#read-only-objects-experimental)
- [保護オブジェクト](#protected-objects-experimental)
- [サンドボックス間の関係](#cross-sandbox-relationships)
- [CLI](#cli)
- [2.xから3.xへの変更点](https://github.com/patriksimek/vm2/wiki/2.x-to-3.x-changes)
- [1.xおよび2.xのドキュメント](https://github.com/patriksimek/vm2/wiki/1.x-and-2.x-docs)
- [貢献](https://github.com/patriksimek/vm2/wiki/Contributing)
## VM
VMは、`require`機能なしで信頼できないコードを同期的に実行するためのシンプルなサンドボックスです。JavaScriptの組み込みオブジェクトとNodeの`Buffer`のみが利用可能です。スケジューリング関数(`setInterval`、`setTimeout`、`setImmediate`)はデフォルトでは利用できません。
**オプション:**
- `timeout` - スクリプトのタイムアウト(ミリ秒)。**警告**: このオプションは`allowAsync=false`と一緒に使用することをお勧めします。さらに、サンドボックスから返されたオブジェクトを操作すると、任意のコードが実行され、タイムアウトを回避される可能性があります。返されたオブジェクトが`typeof`でプリミティブかどうかをテストし、そうでない場合は完全に破棄する必要があります(そのようなオブジェクトでログ記録やエラーメッセージの作成を行うと、再び任意のコードが実行される可能性もあります)。
- `sandbox` - VMのグローバルオブジェクト。
- `compiler` - `javascript`(デフォルト)、`typescript`、`coffeescript`、またはカスタムコンパイラ関数。値が`typescript`または`coffeescript`に設定されている場合、ライブラリはコンパイラが事前にインストールされていることを期待します。**`typescript`には`typescript@6`以前が必要です** — [コンパイラ](#compilers)を参照してください。
- `eval` - `false`に設定すると、`eval`または関数コンストラクタ(`Function`、`GeneratorFunction`など)への呼び出しはすべて`EvalError`をスローします(デフォルト: `true`)。
- `wasm` - `false`に設定すると、WebAssemblyモジュールをコンパイルしようとする試みはすべて`WebAssembly.CompileError`をスローします(デフォルト: `true`)。注: セキュリティ上の理由から`WebAssembly.JSTag`はサンドボックス内から削除されるため、wasmコードはJavaScript例外をキャッチできません。
- `allowAsync` - `false`に設定すると、`async`を使用してコードを実行しようとする試みはすべて`VMError`をスローします(デフォルト: `true`)。
- `bufferAllocLimit` - サンドボックス内からの単一の`Buffer.alloc` / `Buffer.allocUnsafe` / `Buffer.allocUnsafeSlow` / `Buffer(N)` / `new Buffer(N)`リクエストの最大サイズ(バイト単位)。この上限を超えるリクエストは、ホスト側の割り当てを実行せずに同期的に`RangeError`をスローします。デフォルト: `Infinity`(上限なし、完全に後方互換)。メモリ制約のある環境(Docker / Kubernetes / Lambda / serverless)で信頼できないコードを実行する組み込みユーザーは、`timeout`を選択するのと同じように、多層的なDoS防御の一環として有限の上限(例: `32 * 1024 * 1024`)を選択する必要があります。以下の[強化の推奨事項](#hardening-recommendations)を参照してください。
**重要**: タイムアウトは、`run`を通じて実行する同期コードにのみ有効です。タイムアウトは、VMによって返されたメソッドには**適用されません**。タイムアウトが機能しない状況がいくつかあります - [#244](https://github.com/patriksimek/vm2/pull/244)を参照してください。```js
import { VM } from 'vm2';
const vm = new VM({
timeout: 1000,
allowAsync: false,
sandbox: {},
});
vm.run('process.exit()'); // throws ReferenceError: process is not defined
VMから値を取得することもできます。```js let number = vm.run('1337'); // returns 1337
**ヒント**: その他の使用例についてはテストを参照してください。
## NodeVM
`VM` とは異なり、`NodeVM` は通常のNodeのコンテキストと同じ方法でモジュールを`require`することができます。
**オプション:**
- `console` - `inherit` でコンソールを有効化、`redirect` でイベントにリダイレクト、`off` でコンソールを無効化(デフォルト: `inherit`)。
- `sandbox` - VMのグローバルオブジェクト。
- `compiler` - `javascript`(デフォルト)、`typescript`、`coffeescript`、またはカスタムコンパイラ関数(コードとそのファイルパスを受け取ります)。値が`typescript`または`coffeescript`に設定されている場合、ライブラリはコンパイラが事前にインストールされていることを期待します。**`typescript`には`typescript@6`以前が必要です** — [コンパイラ](#compilers)を参照してください。
- `eval` - `false`に設定すると、`eval`または関数コンストラクタ(`Function`、`GeneratorFunction`など)への呼び出しはすべて`EvalError`をスローします(デフォルト: `true`)。
- `wasm` - `false`に設定すると、WebAssemblyモジュールをコンパイルしようとする試みはすべて`WebAssembly.CompileError`をスローします(デフォルト: `true`)。注: セキュリティ上の理由から`WebAssembly.JSTag`はサンドボックス内から削除されているため、wasmコードはJavaScript例外をキャッチできません。
- `bufferAllocLimit` - `VM`と同じ意味論 — サンドボックス内からの単一の`Buffer.alloc`ファミリーリクエストの最大サイズ(バイト単位)。デフォルト: `Infinity`。[堅牢化の推奨事項](#hardening-recommendations)を参照してください。
- `sourceExtensions` - ソースコードとして扱うファイル拡張子の配列(デフォルト: `['js']`)。
- `require` - `true`、オブジェクト、または`require`メソッドを有効にするためのResolver(デフォルト: `false`)。
- `require.external` - 値は`true`、許可された外部モジュールの配列、またはオブジェクトにできます(デフォルト: `false`)。`/node_modules/${any_allowed_external_module}/(?!/node_modules/)`に一致するすべてのパスが`require`可能になります。
- `require.external.modules` - 許可された外部モジュールの配列。ワイルドカードもサポートしているため、例えば`['@scope/*-ver-??]`を指定すると、`@scope/something-ver-aa`、`@scope/other-ver-11`などの形式の名前を持つすべてのモジュールを使用できます。`*`ワイルドカードはパス区切り文字には一致しません。
- `require.external.transitive` - 外部モジュールの推移的依存関係を許可するかどうかを示すブール値(デフォルト: `false`)。**警告**: モジュールが推移的に`require`されると、そのモジュールがロードされる前に不可能だったとしても、その後は任意のモジュールがそれを通常どおり`require`できるようになります。
- `require.builtin` - 許可された組み込みモジュールの配列。すべてに対して`["\*"]`を受け入れます(デフォルト: なし)。**警告**: 新しい組み込みモジュールが追加される可能性があるため、`"\*"`は危険です。
- `require.root` - ローカルモジュールを`require`できる制限付きパス(デフォルト: すべてのパス)。
- `require.mock` - モックモジュールのコレクション(外部または組み込みの両方)。
- `require.context` - `host`(デフォルト)はホスト内でモジュールを`require`し、サンドボックスにプロキシします。`sandbox`はサンドボックス内でモジュールをロード、コンパイル、`require`します。`callback(moduleFilename, ext)`はモジュールごとにコンテキストを動的に選択します。何も指定されない場合のデフォルトはサンドボックスです。`events`を除き、組み込みモジュールは常にホスト内で`require`され、サンドボックスにプロキシされます。
- `require.import` - 起動時にNodeVMにロードされるモジュールの配列。
- `require.resolve` - モジュールが従来のNodeのルックアップパスのいずれにも見つからなかった場合の追加のルックアップ関数。
- `require.customRequire` - ホストからモジュールをロードするための`require`関数の代わりに使用します。
- `require.strict` - `false`にすると、`require`によってロードされたモジュールに厳格モードを強制しません(デフォルト: `true`)。
- `require.fs` - カスタムファイルシステム実装。
- `nesting` - **警告**: スクリプトが任意のホストモジュールを`require`できるNodeVMを作成できるため、これを許可することはセキュリティリスクです。`true`でVMのネストを有効化(デフォルト: `false`)。
- `wrapper` - `commonjs`(デフォルト)はスクリプトをCommonJSラッパーでラップし、`none`はスクリプトによって返された値を取得します。
- `argv` - `process.argv`に渡される配列。
- `env` - `process.env`に渡されるオブジェクト。
- `strict` - `true`でロードされたモジュールを厳格モードにします(デフォルト: `false`)。
**重要**: タイムアウトはNodeVMには効果がないため、`while (true) {}`や同様の悪意のあるコードに対しては無防備です。
**注意**: 許可するモジュールが多ければ多いほど、サンドボックスは脆弱になります。```js
import { NodeVM } from 'vm2';
const vm = new NodeVM({
console: 'inherit',
sandbox: {},
require: {
external: true,
builtin: ['fs', 'path'],
root: './',
mock: {
fs: {
readFileSync: () => 'Nice try!',
},
},
},
});
// Sync
let functionInSandbox = vm.run('module.exports = function(who) { console.log("hello "+ who); }');
functionInSandbox('world');
// Async
let functionWithCallbackInSandbox = vm.run('module.exports = function(who, callback) { callback("hello "+ who); }');
functionWithCallbackInSandbox('world', greeting => {
console.log(greeting);
});
wrapper が none に設定されている場合、NodeVM は同期コードに対して VM により近い動作をします。```js
assert.ok(vm.run('return true') === true);
**ヒント**: その他の使用例については、テストを参照してください。
### 相対パスによるモジュールの読み込み
相対パスでモジュールを読み込むには、スクリプトが文字列の場合、実行中のスクリプトのフルパスをvmの`run`メソッドの2番目の引数として渡す必要があります。ファイル名は、スクリプトによって生成されたスタックトレースに表示されます。```js
vm.run('require("foobar")', '/data/myvmscript.js');
If the script you are running is a VMScript, the path is given in the VMScript constructor.```js const script = new VMScript('require("foobar")', { filename: '/data/myvmscript.js' }); vm.run(script);
### Resolver
リゾルバは `makeResolverFromLegacyOptions` を使用して作成でき、複数の `NodeVM` インスタンスで使用してコンパイル済みモジュールコードを共有できるため、読み込み時間を短縮できる可能性があります。`NodeVM` の最初の例は、`makeResolverFromLegacyOptions` を使用して次のように書き換えることができます。```js
const resolver = makeResolverFromLegacyOptions({
external: true,
builtin: ['fs', 'path'],
root: './',
mock: {
fs: {
readFileSync: () => 'Nice try!',
},
},
});
const vm = new NodeVM({
console: 'inherit',
sandbox: {},
require: resolver,
});
プリコンパイル済みスクリプトを使用することで、パフォーマンスを向上させることができます。プリコンパイル済みのVMScriptは、複数回実行できます。コードはどのVM(コンテキスト)にもバインドされず、実行のたびに、その実行のためだけにバインドされることに注意することが重要です。```js import { VM, VMScript } from 'vm2';
const vm = new VM(); const script = new VMScript('Math.random()'); console.log(vm.run(script)); console.log(vm.run(script));
It works for both `VM` and `NodeVM`.```js
import { NodeVM, VMScript } from 'vm2';
const vm = new NodeVM();
const script = new VMScript('module.exports = Math.random()');
console.log(vm.run(script));
console.log(vm.run(script));
コードは初回実行時に自動的にコンパイルされます。script.compile() を使えばいつでもコードをコンパイルできます。コードがコンパイルされた後は、このメソッドは効果を持ちません。
compiler は javascript(デフォルト)、typescript、coffeescript、または独自の関数を受け付けます。typescript と coffeescript のコンパイラはオプションです — パッケージは自分でインストールしてください。vm2 はどちらにも依存していません。
組み込みの typescript コンパイラには typescript@6 以前が必要です。
vm2 は TypeScript の transpileModule() API を通じてトランスパイルします。TypeScript 7 では、この API がパッケージのエントリポイントから削除されました — そこでの require('typescript') は { version, versionMajorMinor } のみに解決され、代替 API は明示的に不安定な typescript/unstable/* サブパスに置かれていますが、そのいずれも単一ファイルのトランスパイルに相当する機能を提供していません。したがって、vm2 が 7.x でフォールバックできるものは何もありません。
TypeScript 7 がインストールされた状態で compiler: 'typescript' を選択すると、new VMScript(...) / new VM(...) で例外がスローされます。```
VMError: The installed TypeScript (7.0.2) does not expose the transpileModule() API that
vm2's built-in TypeScript compiler uses; it was removed from the package entry point in
TypeScript 7. Install typescript@6 or earlier, or pass your own transpiler as a function:
{ compiler: (code, filename) => javaScriptSource }.
TypeScript 6 を固定するか、独自のトランスパイラを指定してください。JavaScript を返す関数であれば何でも動作するため、TypeScript 7 の `tsc`、esbuild、swc、または型ストリッパーもすべて有効です:```js
import { VM, VMScript } from 'vm2';
import { transformSync } from 'esbuild';
const script = new VMScript('const x: number = 1; x', {
compiler: (code, filename) => transformSync(code, { loader: 'ts', format: 'cjs' }).code,
});
new VM().run(script);
カスタムコンパイラは (code, filename) を受け取り、JavaScript ソースを返さなければなりません。これはサンドボックス化の前に、ホストレルム内で実行されます — 信頼できるコードとして扱い、信頼できない入力からコンパイラを構築してはなりません。
coffee-script がインストールされている必要があります。{ header: false, bare: true } でコンパイルされます。渡した compilerOptions はそれらの設定にマージされます。
コードのコンパイルおよび同期コード実行時のエラーは、try-catch で処理できます。非同期コード実行時のエラーは、Node の process に uncaughtException イベントハンドラをアタッチすることで処理できます。```js
try {
var script = new VMScript('Math.random()').compile();
} catch (err) {
console.error('Failed to compile script.', err);
}
try { vm.run(script); } catch (err) { console.error('Failed to execute script.', err); }
process.on('uncaughtException', err => { console.error('Asynchronous error caught.', err); });
## サンドボックス化されたコードのデバッグ
サンドボックス内で実行されているコードは、通常のプロセスで実行されているかのようにデバッグまたは検査できます。
- ブレークポイントを使用できます(スクリプトファイル名を指定する必要があります)
- `debugger` キーワードを使用できます。
- ステップインを使用して、サンドボックス内で実行されているコードの中に入ることができます。
### 例
/tmp/main.js:```js
import { VM, VMScript } from 'vm2';
import { readFileSync } from 'node:fs';
const file = `${__dirname}/sandbox.js`;
// By providing a file name as second argument you enable breakpoints
const script = new VMScript(readFileSync(file), file);
new VM().run(script);
/tmp/sandbox.js```js const foo = 'ahoj';
// The debugger keyword works just fine everywhere. // Even without specifying a file name to the VMScript object. debugger;
## 読み取り専用オブジェクト(実験的)
サンドボックス化されたスクリプトがプロキシされたオブジェクトのプロパティを追加、変更、または削除するのを防ぐには、`freeze` メソッドを使用してオブジェクトを読み取り専用にすることができます。これは VM 内でのみ有効です。凍結されたオブジェクトは深く影響を受けます。プリミティブ型は凍結できません。
**`freeze` を使用しない例:**```js
const util = {
add: (a, b) => a + b,
};
const vm = new VM({
sandbox: { util },
});
vm.run('util.add = (a, b) => a - b');
console.log(util.add(1, 1)); // returns 0
freeze を使用した例:```js
const vm = new VM(); // Objects specified in the sandbox cannot be frozen.
vm.freeze(util, 'util'); // Second argument adds object to global.
vm.run('util.add = (a, b) => a - b'); // Fails silently when not in strict mode. console.log(util.add(1, 1)); // returns 2
**重要:** 已经代理到 VM 的对象无法冻结。
## 受保护对象(实验性)
与 `freeze` 不同,此方法允许沙盒脚本在对象上添加、更改或删除属性,但有一个例外——无法附加函数。因此,沙盒脚本无法修改 `toJSON`、`toString` 或 `inspect` 等方法。
**重要:** 已经代理到 VM 的对象无法保护。
## 跨沙盒关系```js
const assert = require('assert');
const { VM } = require('vm2');
const sandbox = {
object: new Object(),
func: new Function(),
buffer: new Buffer([0x01, 0x05]),
};
const vm = new VM({ sandbox });
assert.ok(vm.run(`object`) === sandbox.object);
assert.ok(vm.run(`object instanceof Object`));
assert.ok(vm.run(`object`) instanceof Object);
assert.ok(vm.run(`object.__proto__ === Object.prototype`));
assert.ok(vm.run(`object`).__proto__ === Object.prototype);
assert.ok(vm.run(`func`) === sandbox.func);
assert.ok(vm.run(`func instanceof Function`));
assert.ok(vm.run(`func`) instanceof Function);
assert.ok(vm.run(`func.__proto__ === Function.prototype`));
assert.ok(vm.run(`func`).__proto__ === Function.prototype);
assert.ok(vm.run(`new func() instanceof func`));
assert.ok(vm.run(`new func()`) instanceof sandbox.func);
assert.ok(vm.run(`new func().__proto__ === func.prototype`));
assert.ok(vm.run(`new func()`).__proto__ === sandbox.func.prototype);
assert.ok(vm.run(`buffer`) === sandbox.buffer);
assert.ok(vm.run(`buffer instanceof Buffer`));
assert.ok(vm.run(`buffer`) instanceof Buffer);
assert.ok(vm.run(`buffer.__proto__ === Buffer.prototype`));
assert.ok(vm.run(`buffer`).__proto__ === Buffer.prototype);
assert.ok(vm.run(`buffer.slice(0, 1) instanceof Buffer`));
assert.ok(vm.run(`buffer.slice(0, 1)`) instanceof Buffer);
コマンドラインでvm2を使用する前に、npm install vm2 -gでグローバルにインストールしてください。```sh
vm2 ./script.js
## ハードニング推奨事項
vm2はサンドボックスエスケープ(信頼されていないコードがホストレルムへのアクセスを取得すること)を防止します。ただし、それ自体では、あらゆる形態のリソース枯渇やサービス拒否(DoS)を防ぐわけではありません。信頼されていないコードを実行する組み込み側は、サンドボックスの周囲に以下の多層防御を追加する必要があります。
### 1. `bufferAllocLimit` でメモリ割り当てを制限する
攻撃者が制御する `N` を指定した単一の `Buffer.alloc(N)` 呼び出しは、V8の `timeout` が割り込めない単一の同期ホストC++割り当てとして実行されます。メモリが制約された環境では、約100バイトのサンドボックスペイロードが100MB以上のホストRSSジャンプを引き起こし、OOMによってホストプロセスをクラッシュさせる可能性があります。個々の割り当てを制限するために `bufferAllocLimit`(例:`32 * 1024 * 1024`)を設定してください:```js
const vm = new VM({
timeout: 1000,
bufferAllocLimit: 32 * 1024 * 1024,
allowAsync: false,
});
この上限は、非推奨の Buffer(N) および new Buffer(N) パスにも適用されます。なお、総計的な枯渇(多数の小さな割り当て、Buffer.concat、Uint8Array、String.repeat、Array(n).fill() など)はこの上限の対象外であることに注意してください。完全なカバレッジのためには、ホスト側のメモリ制限(--max-old-space-size、コンテナ制限、cgroup)と組み合わせてください。
unhandledRejection ハンドラをインストールするサンドボックスコードが async function、async function*、または await using を作成し、その本体がスタックフォーマット中にホストレルムのエラーをトリガーする値をスローする(例: e.name = Symbol(); e.stack)という、ホストプロセスをアボートさせる DoS のクラスが存在します。V8 はレルムの組み込み Promise を介して rejection プロミスを作成するため、vm2 の Promise サブクラスのラップをバイパスし、rejection は unhandledRejection としてホストに漏れ出します。Node 15 以降では、デフォルトの動作としてプロセスが終了します。
これを塞ぐには、観測可能なホストの動作を変更する必要があるため、vm2 はデフォルトでは修正を提供しません。組み込み側は、サンドボックス由来の rejection を飲み込む(またはログに記録する)プロセスレベルのハンドラをインストールする必要があります:```js // Recommended: filter rejections that originated inside vm2 and swallow them, // while letting your own host-side rejections propagate. process.on('unhandledRejection', (reason, promise) => { // Heuristic: rejections from the sandbox frequently surface as values // without proper Error semantics, or with stacks pointing at vm.js. // Adjust the predicate to match your application. if (looksLikeSandboxOrigin(reason)) { return; // swallow — don't terminate the process } // Otherwise: handle (or rethrow) as normal for your host code. yourLogger.error('unhandled rejection', reason); });
アプリケーションに他の未処理のリジェクションの発生源がない場合、包括的なスワロー+ログは許容されます:```js
process.on('unhandledRejection', reason => {
yourLogger.warn('swallowed sandbox rejection', reason);
});
スコープ付き修正は、将来のマイナーリリースでオプトインの swallowSandboxUnhandledRejections フラグの背後で提供される可能性があります。それまでは、ホスト側のハンドラーが推奨される緩和策です。
bufferAllocLimit を設定しても、ホストプロセスをワークロードに合わせた --max-old-space-size(または同等のコンテナメモリ制限)で実行してください。この上限は単一割り当てプリミティブから保護します。OSレベルの制限は、総合的な枯渇と、vm2がまだ上限を設定していない将来の割り当てプリミティブから保護します。
require.builtin: ['*'] を非サンドボックス構成として扱う'*' ワイルドカードは、child_process、fs、dgram、net、http、dns を含むほとんどのNode組み込みモジュールに展開されます。これらは完全なホスト機能プリミティブです — require('child_process').execSync('id') は '*' の下でサンドボックスから到達可能です。vm2の '*' セマンティクスは意図的ですが(一部のエンベッダーは信頼済みだが分離されたコードを実行します)、信頼できないコードのデフォルトとして使用すべきではありません。サンドボックスが実際に必要とする最小限のモジュールセットの明示的な許可リストを推奨します。
nesting: true はエスケープハッチであるnesting: true を使用すると、サンドボックスコードが require('vm2') を実行してネストされたNodeVMを構築できます。ネストされたVMの require 構成は、それを構築するサンドボックスコードによって選択され、外側のVMによって制約されません。 具体的には:```js
const vm = new NodeVM({ nesting: true, require: { builtin: [] } });
vm.run( const { NodeVM: NVM } = require('vm2'); // Inner VM's config is whatever the sandbox writes here: const inner = new NVM({ require: { builtin: ['child_process'] } }); inner.run('require("child_process").execSync("id")'); // RCE);
`nesting: true` を設定した場合、実質的にサンドボックスに自分自身と同じ信頼レベルを付与したことになります。**信頼できないコードに対して `nesting: true` を有効にしないでください。** サンドボックス化されたコード自体は信頼できるが、セキュリティ以外の理由で VM スタイルの実行セマンティクス(新しいグローバル、制御されたタイムアウト)が必要な場合にのみ使用してください。
`nesting: true` には**明示的な `require` 設定オブジェクトが必要です**(例: `require: { builtin: [] }` または `require: {}`)。それ以外の形式 — `require: false`、`require: undefined`、`require: null`、または `require` を完全に省略 — は、構築時に `VMError` をスローします(GHSA-m4wx-m65x-ghrr、GHSA-8hg8-63c5-gwmx を置き換え)。これらの形式はすべて NESTING_OVERRIDE のみのリゾルバを生成します: サンドボックスは `require('vm2')` のみ可能で、それ以外は何もできません。これは正当な用途のない純粋なエスケーププリミティブです。すべての require を拒否するには、`nesting: true` を削除してください。ネストされた VM を許可するには、明示的な `require` 設定を提供して、トレードオフが呼び出しサイトで見えるようにしてください。
## 既知の問題
- プロキシ化されたクラスを継承するクラスを定義することはできません。これには `Object.create` でのプロキシ化されたクラスの使用も含まれます。
- 直接 eval は機能しません。
- サンドボックス配列をログに記録すると、プロパティ内で配列部分が繰り返されます。
- ソースコード変換により、関数のソース文字列が異なる場合があります。
- サンドボックス内から node プロセスをクラッシュさせる方法があります。[ハードニングに関する推奨事項](#hardening-recommendations) を参照してください。
- 組み込みの `typescript` コンパイラは、vm2 が使用する `transpileModule()` API を削除した TypeScript 7 以降では動作しません。`typescript@6` を使用するか、独自のトランスパイラを渡してください — [コンパイラ](#compilers) を参照してください。
[npm-image]: https://img.shields.io/npm/v/vm2.svg
[npm-url]: https://www.npmjs.com/package/vm2
[license-image]: https://img.shields.io/npm/l/vm2.svg
[license-url]: https://raw.githubusercontent.com/patriksimek/vm2/resurrection/LICENSE.md
[downloads-image]: https://img.shields.io/npm/dm/vm2.svg
[downloads-url]: https://www.npmjs.com/package/vm2
[snyk-image]: https://snyk.io/test/github/patriksimek/vm2/badge.svg
[snyk-url]: https://snyk.io/test/github/patriksimek/vm2