sandboxを使っていて、広めに許可したつなぎ先の中から特定のドメインだけ確実に遮断したい人向け
料理ブログのビルドのために github.com を丸ごと許可したら、その広い許可を踏み台にデータが外へ出る穴が空く。そういうときに settings.json の sandbox.network.deniedDomains へ危ない通信先を書き、許可の幅はそのままに、ここだけは絶対通すなという例外を確実に効かせる場面で使う。
sandbox(Claude Codeに用意された隔離の仕組み。コマンドが触れるファイルとつなげる通信先を絞り込む箱)を使うと、ビルドのために github.com や *.npmjs.org を広めに許可することになります。ところが内蔵プロキシは「繋ぎ先のホスト名」しか見ません。広く開けた github.com が、データを外へ持ち出す抜け穴になりうるわけです。
sandbox.network.deniedDomains は、その広い許可の中で「ここだけは絶対に通すな」を確実に効かせるための一覧です。許可と拒否が衝突したら拒否が勝ちます。
噛み砕くと
新しい職場の入館証を思い浮かべてください。allowedDomains は「このフロア全体に入っていいよ」という広い許可証です。便利なんですが、フロアの中に1部屋だけ機密書庫があったとします。
deniedDomains は、その書庫のドアにだけ貼る「ここは入室禁止」の札です。フロア全体の許可証を持っていても、この札が貼られたドアだけは開きません。
許可の網を広げたまま、危ない一点だけピンポイントで塞ぐ。そういう道具です。
大事な前提:これは「広く許可した中の例外を塞ぐ」道具
deniedDomains 単体で守りが完成するわけではありません。sandboxのネットワークは、初期状態では事前許可がゼロです。コマンドが新しい通信先につなごうとするたび、毎回確認が出ます。
そこで allowedDomains に github.com などを登録して確認を省く。その「広めの許可」とセットで初めて deniedDomains の出番が来ます。許可設計が先、例外封じが後、という順番です。
「料理ブログのプロジェクト」を例に、実際の動きを見る
料理ブログのサイトを作っているとします。ビルド(公開用ファイルを組み立てる処理)のために外への通信が必要で、でも下書きや会員データは外へ漏らしたくない。この状況で1つずつ設定していきます。
ステップ1: sandboxを有効にして、まず広めに許可する
ビルドには github.com からの取得と、npmjs.org 系からの部品ダウンロードが要ります。settings.json の sandbox の下に書きます。
{
"sandbox": {
"enabled": true,
"network": {
"allowedDomains": ["github.com", "*.npmjs.org"]
}
}
}
*.npmjs.org の * はワイルドカードです。registry.npmjs.org でも cdn.npmjs.org でも、末尾が npmjs.org なら全部まとめて許可します。
ステップ2: ここで初心者がやりがちな勘違い
「広く許可したんだから、あとはsandboxが守ってくれる」と思いがちです。ここが落とし穴。
内蔵プロキシは繋ぎ先のホスト名を見て許可を判断するだけで、TLS(通信を暗号化する仕組み)の中身までは開けて確認しません。だから github.com を許した瞬間、そこを見せかけの宛先にしてデータを外へ運ぶ抜け穴が理屈の上で生まれます。
ステップ3: 危ない一点を deniedDomains で塞ぐ
たとえば社内の保管先 sensitive.cloud.example.com へは、何があっても料理ブログのビルド中に通信させたくないとします。deniedDomains に書きます。
{
"sandbox": {
"enabled": true,
"network": {
"allowedDomains": ["github.com", "*.npmjs.org"],
"deniedDomains": ["sensitive.cloud.example.com"]
}
}
}
これで広い許可は残しつつ、この1か所だけ確実に閉じられます。
ステップ4: 衝突したらどっちが勝つか
仮に allowedDomains に *.example.com という広い許可があり、deniedDomains に sensitive.cloud.example.com があったとします。後者は前者にもマッチします。
公式の定義では、両方に当たったとき deniedDomains が優先します。拒否が勝つ。広い許可をいくら重ねても、拒否の札が貼られた先だけは開きません。
ステップ5: 拒否はワイルドカードでまとめて指定できる
deniedDomains は allowedDomains と同じワイルドカードの書き方が使えます。*.example.com と書けば、a.example.com も b.example.com もまとめて塞げます。1個ずつ手書きしなくていい。
ステップ6: 管理者が許可を締めても、拒否は効き続ける
会社で管理されたパソコンだと、管理者が allowManagedDomainsOnly をオンにして「許可リストは管理設定のものだけ有効、各自の許可は無視」と締めることがあります。
このとき許可は管理設定だけになりますが、deniedDomains はすべての設定元からマージされ続けます。あなたがプロジェクト側に書いた拒否も、ローカルに書いた拒否も、ちゃんと効きます。拒否は弱められない方向で設計されています。
つまり sandbox.network.deniedDomains は何をしてくれるのか
- やってくれる: 広く許可した通信先の中から、特定のドメインだけを名指しで塞ぐ。許可と衝突したら拒否を優先する。管理者が許可を締めても拒否は全設定元から効かせ続ける
- やってくれない: TLSの中身を開けての検査はしない。あくまでホスト名での判定。完全な遮断が要件なら別の手当てが要る
- 意味が薄い場面: そもそも
allowedDomainsを狭く絞っていて広い許可が無いなら、塞ぐべき例外が生まれにくく出番が少ない
使いどころ3シナリオ(具体題材で再現)
シナリオ1: 料理ブログのビルドで GitHub を丸ごと許したとき
料理ブログの公開用ファイルを組み立てるのに github.com を許可します。広く開けたので、下書き記事や会員リストを外へ運ぶ通り道になりうる。そこで自社の保管先 sensitive.cloud.example.com を deniedDomains に1行入れて、ビルド中はそこへ一切つながせない。許可の幅は変えず、危ない宛先だけ閉じる形です。
シナリオ2: 家計簿アプリで部品取得は許したいが分析先は塞ぎたいとき
家計簿アプリの開発で *.npmjs.org から部品を落とすのは許可したい。ただ、入れた部品が勝手に行動データを送る分析用の宛先には繋がせたくない。怪しい送信先を deniedDomains に *.telemetry.example.net のようにワイルドカードでまとめて登録すれば、部品取得は通したまま送信側だけ封じられます。
シナリオ3: 会社支給パソコンで管理者の許可設定の上に自分で1枚足したいとき
会社支給のパソコンで allowManagedDomainsOnly が効いていて、許可は管理設定のものしか通りません。それでも自分のプロジェクトでは特定の決済先 pay.example.com へは絶対つながせたくない。プロジェクト側の deniedDomains に書けば、管理設定の締めとは無関係に効きます。拒否だけは自分で上乗せできる、という設計が活きる場面です。
初心者が踏みやすい落とし穴
- 広く許可すれば安全だと思い込む。内蔵プロキシはホスト名でしか判定せず、TLSの中身を見ません。
github.comのような広い許可はデータ持ち出しの抜け穴になりうるので、危ない先はdeniedDomainsで確実に塞ぐ - 許可と拒否が衝突したらどっちが勝つか分からないまま放置する。両方に当たったら
deniedDomainsが優先します。拒否が勝つ、と覚えておけば設計に迷いません - 管理者の締め設定で拒否も無効になると勘違いする。
allowManagedDomainsOnlyがオンでも、deniedDomainsはユーザー・プロジェクト・ローカルすべての設定元から効き続けます。拒否は弱まりません - ワイルドカードが使えないと思って1個ずつ書く。
allowedDomainsと同じ*.example.comの書き方が使えます。サブの宛先をまとめて塞げます - これだけ書けばTLSの中身まで検査して完全遮断してくれると期待する。プロキシはホスト名判定だけ。中身まで見て確実に遮断したい要件なら、TLSの中身を検査する別立てのプロキシを用意する必要があります
- 拒否だけ書いて許可設計を放置する。初期状態は事前許可ゼロで初回確認が出ます。
deniedDomainsは「広く許可した中の例外を塞ぐ」もの。許可とセットで考える - 書く場所を間違える。
settings.jsonのsandboxの下のnetworkの中に書きます。トップに直書きしても効きません
書き方
settings.json の sandbox → network → deniedDomains に、塞ぐドメインを並べて書く(ワイルドカード *.example.com も使える)
やってみるとこうなる
入力
{
"sandbox": {
"enabled": true,
"network": {
"allowedDomains": ["github.com", "*.npmjs.org"],
"deniedDomains": ["sensitive.cloud.example.com"]
}
}
}
出力例
sandbox内のコマンドは github.com と *.npmjs.org へはつながるが、sensitive.cloud.example.com への外向き通信だけは拒否される。allowedDomains に広い許可があってその宛先に当たっても、deniedDomains が優先して塞ぐ。
このページに出てきた言葉
- sandbox(サンドボックス)
- Claude Codeがコマンドを実行するとき、触れるファイルとつなげる通信先を制限して閉じ込める箱のような仕組み
- deniedDomains
- 外への通信でブロックするドメインの一覧。<code>sandbox.network.deniedDomains</code> に書く
- allowedDomains
- 外への通信で許可するドメインの一覧。<code>github.com</code> や <code>*.npmjs.org</code> のように登録する
- allowManagedDomainsOnly
- 管理されたパソコンで使う締め設定。許可リストを管理設定のものだけに限定する。ただし拒否はこの設定に関係なく全設定元から効く
- ワイルドカード
- <code>*</code> を使って複数の通信先をまとめて指す書き方。<code>*.example.com</code> は <code>example.com</code> で終わる住所すべてに当たる
- プロキシ
- sandboxの中の通信を一度受け止め、許可リストと照らし合わせてから通す中継役のプログラム。ホスト名だけ見て判断する
- TLS
- 通信を暗号化して途中で中身を盗み見られないようにする仕組み。内蔵プロキシはこの中身を開けては見ない
- domain fronting
- 許可された見せかけのホスト名を使って、実際は別の通信先へつなぐ抜け道の手口
- data exfiltration
- 守られているはずのデータを、許可された通信路を踏み台にして外へ持ち出すこと