WASMランタイムによるサンドボックス化
プロセスやVMより軽い隔離を、起動1ms未満・容量数MBで実現できる。WASMのスタックマシン検証とWASIのcapabilityモデルが攻撃面をどう縮小するかを原理から整理します。
- 1.WASMは実行前にモジュール全体を静的検証し、線形メモリの外へは番地計算上そもそも出られない構造でサンドボックス化する。
- 2.WASIはPOSIX的な暗黙の名前空間ではなく、起動時に渡されたcapability(ファイルディスクリプタ相当のハンドル)だけにアクセスを絞る。
- 3.コンテナ・マイクロVMより起動が桁違いに速く常駐も小さいが、隔離の壁はカーネルではなくランタイム自身の実装品質に依存する。
プロセス隔離の代わりに何を使うか
コンテナは namespace・cgroup・capability・seccomp を組み合わせて隔離しますが、隔離の単位は依然として「OSプロセス」であり、ホストカーネルを共有します。マイクロVMはハードウェア仮想化で壁を引き直しますが、ゲストカーネルの起動コストが乗ります。WASM(WebAssembly)ランタイムは第三の道です。プロセスでもVMでもなく、言語非依存のバイトコードVMを隔離境界にする発想で、起動速度と隔離強度を同時に狙います。
スタックマシンと静的検証がつくる壁
WASMモジュールはロード時にランタイムが単一パスで検証します。命令列がスタック上でどの型をやり取りするか(i32/i64/f32/f64 など)をすべての分岐で追跡し、型不整合や、存在しない関数・ローカル変数・グローバル変数のインデックス参照、構造化されていない制御フローがあれば実行前に拒否します。この検証はCのunsafeなポインタ演算のような「実行してみないと壊れるか分からない」コードを実行前に排除する点が、ネイティブコードのサンドボックスとの決定的な違いです。
隔離の核はメモリモデルにあります。WASMの各インスタンスは線形メモリと呼ぶ1枚の連続バイト配列だけを持ち、ロードやストア命令はすべてこの配列内のオフセットとして解決されます。実装は境界チェック付きの配列アクセス、またはガードページを敷いた仮想アドレス予約のどちらかでこれを実現し、いずれの方式でもモジュールのコードが線形メモリの外を指すポインタを組み立てる手段を持ちません。加えて関数呼び出しはモジュール内の固定インデックスを指す直接呼び出し(call)か、テーブルと型シグネチャの一致を実行時にチェックする間接呼び出し(call_indirect)のいずれかに限られ、任意の生アドレスへ飛ぶ形では届きません。
「実行前の静的検証でメモリ安全性を保証し、プロセス分離なしに複数のコードを同一アドレス空間に安全に同居させる」という発想自体は、1990年代のSoftware Fault Isolation(SFI)の系譜です。WASMはこれをブラウザの持ち運び可能なバイトコードという形で汎用化し、サーバーサイドにも転用したものと捉えると理解が早くなります。
この構造の帰結として、WASMモジュールはデフォルトでは何もできません。ファイルを開く命令もソケットを張る命令も、命令セットに存在しないからです。外界とやり取りする唯一の経路は、ホストが明示的に注入した「インポート関数」の呼び出しに限られます。ここに capability ベースのセキュリティモデルの土台があります。
WASI:暗黙の名前空間を廃したシステムインターフェース
言語ランタイムがファイルやネットワークを使うには、POSIXに相当する標準インターフェースが要ります。これを定義するのが WASI(WebAssembly System Interface)です。WASIの設計はPOSIXと似た関数群(path_open・fd_read・fd_write 等)を持ちながら、アクセス制御の哲学が根本的に異なります。
| 観点 | POSIX | WASI |
|---|---|---|
| 名前空間 | グローバルな単一のファイルパス空間を全プロセスが暗黙に見る | 起動時に渡された相対ディレクトリハンドルの範囲しか見えない |
| 権限の起点 | UID/GIDに基づく実行時チェック(open時にACLを照合) | capability(ハンドル)を持たないAPI呼び出しは構文的に不可能 |
| 絞り込みの手段 | chroot・AppArmor等を後から追加で重ねる | 起動時にホストが渡すハンドルの集合そのものが権限 |
| 典型的な事故 | パストラバーサル(../での脱出) | 渡されていないディレクトリはそもそも名前で参照できない |
具体的には、モジュールは/etc/passwdのような絶対パス文字列を渡しても、それを解決する術がありません。WASIのpath_openは既に開かれたディレクトリハンドル(capability)を起点にした相対パス解決しか許さず、ホストが起動時にどのディレクトリハンドルも渡さなければ、モジュールはファイルシステムに触れる方法を持ちません。これは「実行時にパスを検査して拒否する」のではなく、そもそも到達する経路が存在しないという強さの違いです。ネットワークやクロックも同様に、ホストが明示的に許可したソケットや権限だけがモジュールに見えます。
capabilityベースのモデルでは「これはアクセスしてよいか」を都度チェックするのではなく、「アクセス手段(ハンドル)を持っているかどうか」自体がアクセス可否そのものになります。最小権限は設計上デフォルトで、後付けの制限ではありません。この考え方はマイクロカーネルのポート capability(例えばMachのメッセージポート)と系譜が近く、WASIはそれをユーザー空間のABIとして再実装したものです。
起動速度の内訳とコンテナ・unikernelとの比較
WASMランタイムが「軽い」のは偶然ではなく、削れる層が構造的に少ないためです。
| 観点 | コンテナ(namespace/cgroup) | マイクロVM(Firecracker等) | WASMランタイム |
|---|---|---|---|
| 隔離の壁 | カーネル機構による論理分離(カーネルは共有) | ハードウェア仮想化によるゲスト/ホスト分離 | バイトコード検証+線形メモリのアドレス空間内分離 |
| 起動時に必要な作業 | namespace生成・cgroup設定・rootfsマウント | ゲストカーネルのブート・デバイス初期化 | モジュール検証・線形メモリ確保・関数テーブル構築 |
| 典型的な起動時間 | 数十〜数百ms | 約125ms前後 | 1ms未満〜数ms |
| 常駐メモリ | アプリ次第(数MB〜) | ゲストカーネル分を含め数MB〜 | 線形メモリ実サイズのみ(KB〜数MB) |
| OSカーネルの要否 | ホストカーネル1つを全コンテナで共有 | ゲストごとに独立カーネルを起動 | カーネルを介さずランタイムのプロセス内で実行可能 |
コンテナは軽量とはいえ、rootfsのマウントや複数の namespace 生成といったカーネル側のセットアップコストを起動のたびに払います。マイクロVMはさらにゲストカーネルのブート自体が必要です。WASMランタイムは新しいOSプロセスもゲストカーネルも起動せず、既に動いているホストプロセスの中でモジュールをロードして即座に実行に移れるため、コールドスタートが1桁から2桁短くなります。unikernelはアプリとOS機能を単一アドレス空間に静的リンクして起動を縮める点でWASMと発想が近い一方、unikernelは依然としてハードウェア(ないし仮想ハードウェア)上でブートするイメージであるのに対し、WASMモジュールはホストプロセスに動的にロードされるデータに近く、ブートという概念自体を持ちません。
何を失っているか
この軽さは無償ではありません。第一に、**隔離の壁がハードウェアではなくソフトウェア(ランタイム実装)**にある点です。マイクロVMのゲスト/ホスト境界はCPUの仮想化支援機能が引くのに対し、WASMの境界はランタイムの検証器とインタプリタ/JITコンパイラのコードが正しく実装されている前提に依存します。検証器やJITにバグがあれば、線形メモリ外への書き込みという形で境界を破られる可能性があり、実際に主要ランタイムでも境界チェック省略に類する脆弱性が報告されてきました。第二に、WASI自体はプロセス並行性・シグナル・高精度なリアルタイムI/O多重化など、POSIXが提供してきた機能の一部を意図的にまだ十分にカバーしていません。第三に、数値演算中心ではないワークロード(重いシステムコール往復や特殊なハードウェアアクセス)では、capabilityの受け渡しやホスト関数呼び出しの層がオーバーヘッドになります。
WASMの検証とWASIのcapabilityモデルは攻撃面を大きく削りますが、単体で万能ではありません。実運用ではWASMランタイムのプロセス自体をさらにseccompやコンテナで包み、ランタイム実装のバグが仮に境界を破っても外側の壁が残るようにするのが定石です。マイクロVMが「多層防御」を前提にするのと同じ考え方です。
WASMはロード時の静的検証と線形メモリへの閉じ込めにより、プロセスやVMを使わずにコードを隔離する。WASIはPOSIXのような暗黙の名前空間ではなく、起動時に渡されたcapability(ハンドル)だけが権限になる設計で、最小権限がデフォルトになる。結果としてコンテナやマイクロVMより起動が桁違いに速く常駐も小さいが、隔離の壁はハードウェアではなくランタイム実装の正しさに依存するため、他の隔離機構と組み合わせる多層防御が前提となる。
OS Article
WASMランタイムによるサンドボックス化を実務で読む
TL;DRは入口です。実際に選ぶ・使う段階では、何を解決するか、何と比較するか、導入後にどこで詰まるかまで見る必要があります。
解決すること
WASM
比較で見る軸
難易度: advanced / カテゴリ: OS / タグ数: 6
導入後に効く点
WASIはPOSIX的な暗黙の名前空間ではなく、起動時に渡されたcapability(ファイルディスクリプタ相当のハンドル)だけにアクセスを絞る。
先に潰すリスク
用語だけ覚えても、設計・実装・運用でどこに効くかを確認しないと判断を誤る。
- 難易度
- advanced
- カテゴリ
- OS
- タグ数
- 6
判断チェックリスト
- 自社の用途が「WASM / WASI」に近いか確認する。
- 強みである「WASMは実行前にモジュール全体を静的検証し、線形メモリの外へは番地計算上そもそも出られない構造でサンドボックス化する。」が本当に評価軸になるか確認する。
- 注意点の「用語だけ覚えても、設計・実装・運用でどこに効くかを確認しないと判断を誤る。」を運用で吸収できるか確認する。
- 公開値や仕様値は、対象プラン・対象機種・対象リージョンまで確認する。
- 既存システム、ID、ネットワーク、監視、バックアップとの接続方法を先に洗い出す。
- 小さく試してから、本番移行、権限設計、障害時手順、コスト監視を決める。