JavaScriptにおけるサンドボックスの深堀り
Ethan Miller
Product Engineer · Leapcell

JavaScriptにおいて、サンドボックスとは、実行中のコードを隔離し、アプリケーションやシステムの他の部分に不必要な影響やセキュリティリスクを引き起こすことを防ぐために使用されるセキュリティメカニズムです。サンドボックスは、コードが外部環境に影響を与えることなく実行できる制御された環境を提供し、ユーザーデータとシステムセキュリティを保護します。
ブラウザでは、サンドボックスは通常、各タブに対してブラウザが提供する隔離された環境を指します。この隔離により、2つのページが同一オリジンポリシー(つまり、同じプロトコル、ドメイン、ポートを持つ)に従うか、CORS(Cross-Origin Resource Sharing)を介してクロスオリジンアクセスを明示的に許可しない限り、あるタブのJavaScriptコードが別のタブのコンテンツにアクセスできないことが保証されます。Webコードは、IPC(Inter-Process Communication)チャネルを介してブラウザカーネルプロセスと通信する必要があり、通信プロセスはセキュリティチェックを受けます。サンドボックス設計の目的は、信頼できないコードが特定の環境内で実行されることを許可し、隔離ゾーン外のリソースへのアクセスを制限することです。
JavaScriptでサンドボックスを使用するケースとは?
JavaScriptでは、サンドボックスは通常、コードの実行環境を隔離および制御するために使用され、コードが安全で制限された環境で実行され、メイン環境への潜在的な損害を回避します。
- サードパーティのJavaScriptの実行: 信頼できない可能性のあるサードパーティのJavaScriptコードを実行する必要がある場合。
- オンラインコードエディタ: 多くのオンラインコードエディタは、ユーザーが提供したコードがページ自体に影響を与えるのを防ぐために、サンドボックスで実行します。
- Webアプリケーションのセキュリティ: ブラウザで異なるソースからのJavaScriptを実行する場合、サンドボックスは権限を制限し、悪意のあるコードが機密リソースにアクセスしたり、危険な操作を実行したりするのを防ぎます。
- プラグインとサードパーティスクリプト: Webアプリケーションがサードパーティのプラグインまたはスクリプトをロードして実行する必要がある場合、サンドボックスはアクセス権を制限し、メインアプリケーションとそのデータのセキュリティを保護します。
- JSONP: サーバーからJSONPレスポンスを解析する場合、返されたデータが信頼できない場合は、サンドボックスを使用して安全に解析し、データを取得できます。
JSONP通信メカニズム
JSONPの動作原理は、<script>
タグにはクロスオリジンの制限がない(歴史的な遺物)という事実にあり、サードパーティサービスとの通信を可能にします。通信が必要な場合、現在のサイトのスクリプトは、サードパーティAPIのURLを指す<script>
要素を作成します。例えば、次のようになります。
<script src="http://www.example.net/api?param1=1¶m2=2"></script>
データを受信するコールバック関数が提供されます(関数名は合意されるか、URLパラメータを介して渡されます)。サードパーティのレスポンスは、JSONでラップされたレスポンスです(したがって、JSONPという用語は、JSON paddingを意味します)。例えば、次のようになります。
callback({ name: 'hax', gender: 'Male' });
これにより、ブラウザはcallback
関数を呼び出し、解析されたJSONオブジェクトをパラメータとして渡します。現在のサイトのスクリプトは、callback
関数内で受信したデータを処理できます。
サンドボックスを使用したJSONPデータの解析の基本的なアプローチ
- 隔離されたiframeをサンドボックスとして作成: メインページにiframeを動的に作成し、JSONPリクエストに対して隔離された実行環境を提供します。このiframeはメインページのDOMにアクセスできず、実行されるコードの影響を制限します。
- iframe内でJSONPリクエストを開始: 作成されたiframeに
<script>
タグを挿入して、返されたJSONPスクリプトが隔離された環境内で実行されるようにします。これにより、返されたスクリプトに悪意のあるコードが含まれていても、その影響はiframe内に限定され、メインページに影響を与えないことが保証されます。 - iframeから安全にデータを取得: iframe内のスクリプトは、メインページのDOMを直接変更することはできませんが、
postMessage
APIなどの定義済みのメソッドを使用して、データをメインページに安全に送信できます。メインページは、ソースを検証しながら、このデータを受信するためのイベントリスナーを設定して、セキュリティを確保する必要があります。 - iframeの動作を制限および監視: 追加のセキュリティ対策として、Content Security Policy (CSP) を使用して、iframeがロードおよび実行できるリソースを制限したり、他のブラウザのセキュリティ機能を利用して、iframeの動作を監視および制御したりすることがあります。
これらの手順に従うことで、JSONPレスポンスに信頼できないデータまたはコードが含まれている場合でも、潜在的な脅威を効果的に隔離および制御し、ユーザーデータとセキュリティを保護できます。
要するに、信頼できないJavaScriptを解析または実行する必要がある場合、実行環境を隔離する場合、または実行中のコード内の特定のオブジェクトへのアクセスを制限する場合、サンドボックスは重要な役割を果たします。
with
+ new Function
を使用したサンドボックスの実装
JavaScriptでは、with
ステートメントとnew Function
を使用して、単純なサンドボックス環境を作成できます。このメソッドは、コードの実行範囲を制限し、グローバル変数へのアクセスや安全でない操作の実行を防ぎます。
with
ブロックスコープ内では、変数アクセスは、スコープチェーンをさらに上に探す前に、提供されたオブジェクトのプロパティを優先します。これにより、実行されたコード内の変数アクセスを効果的に監視できます。
function createSandbox(code) { // サンドボックス内のグローバルオブジェクトとして機能する空のオブジェクトを作成します const sandbox = {}; // withステートメントを使用して、コードのスコープを空のオブジェクトに設定します // new Functionを使用して、コードのアクセスをサンドボックスオブジェクトのみに制限する新しい関数を作成します const script = new Function('sandbox', `with(sandbox) { ${code} }`); // 関数を実行し、サンドボックスオブジェクトを引数として渡します return function () { script(sandbox); }; } // サンドボックス環境の使用 const sandboxedScript = createSandbox('console.log("Hello from the sandbox!"); var x = 10;'); sandboxedScript(); // 出力:Hello from the sandbox! console.log(typeof x); // 出力:undefined、xはサンドボックス内で定義され、外部からはアクセスできないため
ここでは、文字列code
をパラメータとして受け取るcreateSandbox
関数を定義します。この文字列は、サンドボックス環境で実行する必要があるJavaScriptコードを表します。最初に、サンドボックス内のグローバルオブジェクトとして機能する空のオブジェクトsandbox
を作成します。次に、with(sandbox)
ステートメントを使用して、サンドボックス化されたコードの実行環境をこの空のオブジェクトに設定します。これは、すべての変数と関数の定義がサンドボックス内に閉じ込められ、グローバルスコープにアクセスできないことを意味します。
new Function
コンストラクターは、提供されたコード文字列を実行する新しい関数を作成します。これにより、スコープを制限しながらJavaScriptを動的に実行し、外部環境へのアクセスや変更を防ぐことができます。最後に、呼び出されるとサンドボックス化されたコードを実行するクロージャ関数を返します。
制限事項とセキュリティ上の懸念
このメソッドはある程度実行環境を隔離できますが、完全に安全ではありません。with
ステートメントとnew Function
にはセキュリティリスクがあります。特に、サンドボックス化されたコードがFunction
コンストラクター自体にアクセスできる場合、サンドボックスの制限を回避して任意のコードを実行できる可能性があります。簡単に言うと、new Function
+ with
は、行儀の良いユーザーを阻止できるサンドボックス化手法ですが、悪意のあるアクターに対しては万全ではありません。
iframe
を使用したサンドボックスの実装
iframe
を使用してサンドボックス環境を作成することは、Web開発で一般的な手法です。現在のページ内に完全に独立したHTMLページを埋め込むことができ、JavaScriptの実行を効果的に隔離し、スクリプトがメインページのDOMまたはJavaScript環境にアクセスするのを防ぎ、セキュリティを強化します。
HTML構造
まず、HTML構造を設定する必要があります。
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>Sandbox Example</title> </head> <body> <iframe id="sandbox" style="display: none"></iframe> <script src="index.js"></script> </body> </html>
JavaScriptの実装
index.js
では、iframe
のcontentWindow
プロパティを操作して、単純なサンドボックス環境を作成できます。ここでのアイデアは、iframe
内にスクリプトを挿入して実行し、隔離されたコンテキスト内で実行されるようにすることです。
// index.js function createSandbox(callback) { const iframe = document.getElementById('sandbox'); if (!iframe) { return console.error('Sandbox iframe not found'); } // コードを実行する前に、iframeが完全にロードされていることを確認します iframe.onload = function () { const iframeWindow = iframe.contentWindow; // 必要に応じて、サンドボックス内にいくつかの安全なグローバル変数または関数を定義します iframeWindow.safeGlobalVar = { /* 安全なデータまたはメソッド */ }; // コールバック関数を実行し、サンドボックスのwindowオブジェクトを渡して、その中でコードを実行します callback(iframeWindow); }; // クリーンな環境を確保するために、iframeをリロードします iframe.src = 'about:blank'; } // サンドボックスの使用 createSandbox(function (sandboxWindow) { // サンドボックス内でコードを実行します sandboxWindow.eval('console.log("Hello from the sandbox!");'); });
iframe
サンドボックスの制限
iframe
をサンドボックスに使用すると、いくつかの組み込みの制限があります。
- サンドボックス化された
iframe
内の<script>
タグは実行できません。 - AJAXリクエストは許可されません。
- ローカルストレージ(例:
localStorage
、cookie
)にはアクセスできません。 - 新しいポップアップ(
window.open
)を作成できません。 - フォームを送信できません。
- Flashなどのプラグインをロードできません。
ただし、HTML5はsandbox
属性を導入し、セキュリティをさらに強化するための追加の制限を提供します。sandbox
属性は、次の値をサポートしています。
allow-scripts
:スクリプトの実行を許可します。allow-same-origin
:同じオリジンからのドキュメントとのやり取りを許可します。allow-forms
:フォームの送信を許可します。allow-popups
:window.open
で作成されたものなど、ポップアップを許可します。allow-top-navigation
:トップレベルのフレームへのナビゲーションを許可します。
iframe
でsandbox
属性を使用する例を次に示します。
<iframe src="sandbox.html" sandbox="allow-scripts" id="sandbox"></iframe>
メインページとiframe
間の安全な通信
postMessage
APIを使用して、メインページとサンドボックス化されたiframe
間で安全にデータを交換できます。まず、メインページで次の操作を行います。
<!DOCTYPE html> <html> <head> <title>Main Page</title> </head> <body> <iframe src="./sandbox.html" id="sandbox" style="width: 600px; height: 400px"></iframe> <script> var iframe = document.getElementById('sandbox'); // iframeがロードされるのを待ちます iframe.onload = function () { var targetOrigin = 'http://127.0.0.1:5500/'; // iframeの実際のオリジンに置き換えます iframe.contentWindow.postMessage('Hello, sandbox!', targetOrigin); }; // iframeからのメッセージをリッスンします window.addEventListener('message', function (event) { // メッセージソースを検証します if (event.origin !== 'http://127.0.0.1:5500') { return; // 信頼できないソースからのメッセージを無視します } // 受信したメッセージを処理します console.log('Received message from iframe:', event.data); }); </script> </body> </html>
iframe
ページ(sandbox.html
)では、メッセージをリッスンします。
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>Sandbox</title> </head> <body> <script> window.addEventListener('message', function (event) { // メッセージソースを検証します if (event.origin !== 'http://127.0.0.1:5500') { return; // 信頼できないソースからのメッセージを無視します } // 受信したメッセージを処理します console.log('Received message:', event.data); // メインページに応答を送信します event.source.postMessage('Hello, main page!', event.origin); }); </script> </body> </html>
event.origin
を検証し、postMessage
で正確なターゲットオリジンを指定することで、安全な通信を確保し、潜在的なセキュリティ脆弱性を防ぐことができます。
Web Workersを使用したサンドボックスの実装
Web Workersをサンドボックスとして使用するには、Worker内で実行するJavaScriptコードを含むBlob
オブジェクトを動的に作成します。このメソッドでは、コードをメインページの環境から隔離しながら、別のスレッドで任意のJavaScriptコードを実行できます。これにより、コードを安全に実行する方法が提供されます。
function workerSandbox(appCode) { var blob = new Blob([appCode]); var appWorker = new Worker(window.URL.createObjectURL(blob)); } workerSandbox('const a = 1; console.log(a);'); // 出力:1 console.log(a); // ReferenceError: a is not defined
このアプローチは、Web Workersを活用して、信頼できないコードを隔離された環境で実行し、メインページに干渉しないようにします。Web Workersは、計算量の多いタスクを処理する場合に特に役立ちます。別のスクリプトを実行しながら、UIの応答性を維持できるためです。
まとめ
JavaScriptサンドボックスとは、コードを実行およびテストできる隔離された実行環境であり、メインアプリケーションの状態またはデータに影響を与えません。グローバル変数と関数へのアクセスを制限することで、サンドボックスは、潜在的なセキュリティリスクやデータ漏洩を防ぎながら、信頼できないコードを安全に実行する方法を提供します。サンドボックスは、悪意のあるスクリプトまたは予測できないスクリプトからアプリケーションを保護するために不可欠です。
サンドボックスを実装するさまざまな方法には、次のものがあります。
-
with
+new Function
:- 基本的な隔離を提供します。
- サンドボックス化されたコードが
Function
コンストラクターを介してエスケープする可能性があるため、完全に安全ではありません。
-
iframe
サンドボックス:- 埋め込みiframeを使用して、別の実行環境を作成します。
- セキュリティが向上しますが、いくつかの制限があります(例:制限された
localStorage
およびAJAX
リクエスト)。 postMessage
と組み合わせて、安全なデータ交換を行うことができます。
-
Web Workers:
- 別のスレッドでコードを実行します。
- 強力な隔離を提供しますが、DOMへの直接アクセスはありません。
- 信頼できないスクリプトまたは計算コストの高いスクリプトの実行に最適です。
サンドボックスを使用する場合
サンドボックスは、次の場合に役立ちます。
- 信頼できないJavaScriptを安全に実行または解析する必要がある場合。
- メインアプリケーションへのコードの干渉を防ぐために、実行環境を隔離する場合。
- 実行中のコードの特定のオブジェクトまたはAPIへのアクセスを制限する必要がある場合。
適切なサンドボックス技術を選択することで、開発者はメインアプリケーションへのリスクを最小限に抑えながら、セキュリティを向上させ、スクリプトの安全な実行を保証できます。
Leapcellは、Node.jsプロジェクトをホストするための最良の選択肢です。
Leapcellは、Webホスティング、非同期タスク、Redis向けの次世代サーバーレスプラットフォームです。
多言語サポート
- Node.js、Python、Go、またはRustで開発。
無料で無制限のプロジェクトをデプロイ
- 使用量のみを支払い — リクエストなし、請求なし。
比類のないコスト効率
- アイドル料金なしの従量課金制。
- 例:$25で、平均応答時間60msで694万リクエストをサポートします。
合理化された開発者エクスペリエンス
- 簡単なセットアップのための直感的なUI。
- 完全に自動化されたCI/CDパイプラインとGitOps統合。
- 実用的な洞察のためのリアルタイムメトリックとロギング。
簡単なスケーラビリティと高性能
- 簡単な高並行処理を処理するための自動スケーリング。
- 運用オーバーヘッドゼロ — 構築に集中するだけです。
ドキュメントで詳細をご覧ください。
Xでフォローしてください:@LeapcellHQ