
2026/11/08 23:42
Deno のセキュリティモデルを好まない(2024)
RSS: https://news.ycombinator.com/rss
要約▶
Japanese Translation:
2024 年 8 月 31 日 に公開された本記事は、Deno のセキュリティモデルが、サンドボックスを模倣するに過ぎるパーミッションシステムに依存しているため、本質的に欠陥があり誤導的であると主張しています。「デフォルトで安全(secure by default)」としてマーケティングされ、
--allow-read や --allow-run などのフラグが存在するにもかかわらず、ランタイムは stdin/stdout を介してターミナルプロンプトを攻撃者によって操作できるようにし、PATH および LD_PRELOAD のように制限のない環境変数へのアクセスを許可し、動的リンカーのトリックを用いてサンドボックスから脱出することを可能にしています。最近のパッチですら、セキュリティ判断のために攻撃者制御のチャンネルを使用するという核心にあるアーキテクチャ上の問題を解決できていません。著者は、「巧妙ではない悪意のあるコードに対する保護」という概念が、信頼できないコードに対して危険な虚偽の安全感を与えるものだと批判しています。したがって、本稿は内部のサンドボックス化を捨てて bwrap(バブルワップ)を採用することを推奨し、真のプロセス隔離を実現するとともに、適切な外部サンドボックス化なしで特権プロセス内で信頼できないコードを実行することは、特定のパーミッションの組み合わせに関わらず深刻なリスクであると警告しています。本文
Deno のパーミッションシステム:本質的脆弱性と誤解のリスクについて
2024 年 8 月 31 日に公開された記事において、著者は Deno のパーミッション(権限)システムがセキュリティ的に根本的な弱点を含み、誤解を招くアプローチであると指摘しています。以下に論点と推奨事項を整理します。
Deno とパーミッションの仕組み
Deno の概要
- JavaScript 用のランタイム環境です。
- 標準ライブラリ、パッケージマネージャー、TypeScript トランスパイラなどの機能を統合していますが、JavaScript を直接コンパイルするのではなく V8 ランタイムを再利用しています。
- 象徴的な機能である「デフォルトで安全」を実現するために、パーミッションシステムを採用しています。
パーミッションの基本概念
Deno で外部世界へのアクセス(ファイル読み取りやコマンド実行など)を行うには、明示的に許可が必要です。
- 起動時の指定: コマンドライン引数でアクセス範囲を制限できます。
# 例:/tmp/dir からのみ読み込み、特定の コマンドのみ実行可能 deno run --allow-read=/tmp/dir --allow-run=uname code.ts - 実行時のリクエスト: プログラム内で
を呼び出すと、ターミナル上にプロンプトが表示されます。Deno.permissions.request()
プロンプト表示例
以下のコードを実行すると、ユーザーに承認を求めるウィンドウ(ターミナル上)が現れます。
const r = { name: "read", path: "/tmp/dir" } as const; await Deno.permissions.request(r);
ターミナル上の表示:
┌ ⚠️ Deno requests read access to "/tmp/dir". ├ Requested by `Deno.permissions.request()` API. ├ Run again with --allow-read to bypass this prompt. └ Allow? [y/n/A] (y = yes, allow; n = deny; A = allow all read permissions) >
問題点の分析
1. プロンプト表示手法の脆弱性
ターミナル上での許可プロンプトは、GUI ウィンドウのような安全なインターフェースではなく、標準出力(stdout)と標準入力(stdin)のみを利用しています。
- バンド内(in-band)通信の問題:
- 通常、コマンドは stdout に情報を送り込みます。ターミナルはそれを表示しますが、シェルがこれを理由に別のコマンドを実行することは稀です。
- しかし、Deno は悪意のあるコードが stdout や stdin を恣意的に操作することを許容します。
- 攻撃シナリオ:
- 攻撃者がターミナルの色を変更してプロンプトを隠したり、ユーザーの入力を誘導・操作したりできます。
- **「Enter キーを押して続行」**などの表示は標準的ですが、実際の許可メカニズムに対する欺瞞(トリック)となり得ます。
- 根本的な欠陥:
- 攻撃者が制御するチャネル(ターミナル)を通じて「セキュリティに敏感な情報」を受け取ることは危険です。ウェブページでパスワード入力画面を表示し、実際には別のドメインにデータを送信するようなリスクと同じです。
- 非標準的なターミナル機能との相互作用も予測不可能であり、追加のリスクになります。
補足:
との違いは、sudoがパスワード入力を要求する前に他のコードを実行しない点にあります。ターミナルの状態を操作してsudoを騙すのは、ターミナル自体が脆弱であることを意味します。sudo
2. --allow-run
の不徹底な実装
--allow-runコマンド指定の簡略化(例:
--allow-run=uname)はセキュリティ上致命的な弱点です。
-
問題の本質:
という文字列は、フルパスではなく PATH に設定されたディレクトリを順番に検索して見つけたものです。uname- プログラムが一意の名前で識別されることを前提としておりません。
-
攻撃例 1:PATH 操作による実行: 環境変数
を変更するだけで、意図したコマンドではなく、悪意のあるスクリプトが起動します。PATH$ cat t.ts // Deno コードで uname を呼び出す const command = new Deno.Command("uname", { ... }); $ # 実際のシステム上の uname に触るのではなく $ echo '#!/bin/sh' > /tmp/tmp.7ofmKaNW83/uname $ echo 'printf "lol"' >> /tmp/tmp.7ofmKaNW83/uname $ chmod +x /tmp/tmp.7ofmKaNW83/uname $ deno run --allow-run=uname t.ts lol -
攻撃例 2:LD_PRELOAD を介したサンドボックス脱出: 動的にリンクされた実行ファイル(大部分の実行ファイル)は、環境変数で構成可能です。
を指定することで、任意のコードを実行できます。LD_PRELOAD// C コード:t.c #include <stdio.h> __attribute__((constructor)) void lol() { puts("lol"); }// TypeScript コード const command = new Deno.Command("uname", { env: { 'PATH': '/tmp/tmp.7ofmKaNW83', 'LD_PRELOAD': '/tmp/tmp.7ofmKaNW83/liblol.so' // サンドボックス脱出 }, }); -
開発者の見解: Deno の開発者は、「頭が良すぎない悪意のあるコード」を防ぐことが目的であると述べましたが、これは実質的に「環境設定やコマンドの特定パッチを修正すれば安全」という誤った安心感を与えるものです。
のような特定のユースケースでは有効ですが、一般用途のサンドボックス化には不十分です。git-over-SSH- ユーザーは
を指定するだけで、そのエディタが$EDITOR
を設定されれば全データが消えるリスクを認識していない可能性があります。VIMINIT='!rm -rf /*'
結論と推奨事項
Deno の現状評価
- 擬似的なサンドボックス: Deno は標準ライブラリのフィルタリングでシステムコールの制限を模倣していますが、プロセス自体はサンドボックス化されていません。
- 危険性:
- 「権限なし」で実行しているつもりでも、環境変数やシンボリックリンク、動的ライブラリ経由で脱出可能であるため、「権限なし」という状態は幻想です。
- ユーザーに複雑なパーミッションの組み合わせを理解させることを暗黙に要求しており、誤運用を招きます。
安全な利用条件(限界)
Deno を完全に安全にするのは不可能ですが、以下の制約を厳格に守ることでリスクを減らせます:
- 危険な権限の完全排除:
のようなコマンド実行権限は一切使用しない。--allow-run
- 環境変数の管理:
- 環境変数を設定せず、特に
も避ける(メモリエラーや libc 関数の影響リスクがあるため)。--allow-env
- 環境変数を設定せず、特に
- プロンプトの無効化:
- ターミナルを欺かれることを防ぐため、できれば
を使用。--no-prompt
- ターミナルを欺かれることを防ぐため、できれば
- シンボリックリンクの注意:
を指定したディレクトリ内のシンボリックリンクに細心の注意を払う。--allow-{read,write}
- リソース枯渇への対応:
- CPU やメモリの制限はパーミッションでは制御できないため、別途管理する必要がある。
著者の推奨結論: 「適切なサンドボックス」を使用すべきであり、Deno のセキュリティモデルを支持しない立場です。非対話的なコンテキストでリソース消費のみを制御したい場合でも、「権限なし」という状態を信頼するのは罠です。標準ライブラリの API 組み合わせによる脱出経路が存在することを無視するべきではありません。
推奨代替案
- 信頼できないコードを実行する場合、
(bubblewrap) を使用してください。bwrap- 真にサンドボックス化された環境を提供します。
- システムコールレベルでの制限が可能で、環境変数や動的リンクのリスクも軽減できます。
開発者へのメッセージ
- 技術的な意見の不一致は起こり得ますが、いじめを通じて解決された技術的問題は存在しません。
- Deno の開発者に批判的な投稿を繰り返すのは、誰も助けられないため控えてください。