Skip to content

非公式本サイトは非公式の日本語ドキュメントであり、Cloudflare 公式サイトではありません。最新情報はdevelopers.cloudflare.comをご確認ください。

セキュリティモデル

最終更新 Markdown で表示Agent セットアップ

Sandbox SDK は Containers の上に構築されています。各サンドボックスは独自の VM で動き、強い分離を提供します。

コンテナの分離

各サンドボックスは別の VM で動き、完全に分離されます。

  • ファイルシステムの分離 - サンドボックスは、ほかのサンドボックスのファイルにアクセスできません
  • プロセスの分離 - あるサンドボックスのプロセスは、ほかのサンドボックスのプロセスを見たり影響したりできません
  • ネットワークの分離 - サンドボックスは別々のネットワークスタックを持ちます
  • リソース制限 - CPU、メモリ、ディスクのクォータはサンドボックスごとに適用されます

基盤となるコンテナプラットフォームのセキュリティ詳細は Containers のアーキテクチャ を参照してください。

1 つのサンドボックス内

1 つのサンドボックス内のコードは、リソースを共有します。

  • ファイルシステム - すべてのプロセスが同じファイルを見ます
  • プロセス - すべてのセッションがすべてのプロセスを見られます
  • ネットワーク - プロセスは localhost 経由で通信できます

完全に分離するには、ユーザーごとに別のサンドボックスを使います。

// Good - Each user in separate sandbox
const userSandbox = getSandbox(env.Sandbox, `user-${userId}`);

// Bad - Users sharing one sandbox
const shared = getSandbox(env.Sandbox, 'shared');
// Users can read each other's files!

入力検証

コマンドインジェクション

コマンドで使う前に、ユーザー入力を必ず検証してください。

// Dangerous - user input directly in command
const filename = userInput;
await sandbox.exec(`cat ${filename}`);
// User could input: "file.txt; rm -rf /"

// Safe - validate input
const filename = userInput.replace(/[^a-zA-Z0-9._-]/g, '');
await sandbox.exec(`cat ${filename}`);

// Better - use file API
await sandbox.writeFile('/tmp/input', userInput);
await sandbox.exec('cat /tmp/input');

認証

サンドボックスへのアクセス

サンドボックス ID は基本的なアクセス制御になりますが、暗号学的に安全ではありません。アプリケーション層の認証を追加してください。

export default {
  async fetch(request: Request, env: Env): Promise<Response> {
    const userId = await authenticate(request);
    if (!userId) {
      return new Response('Unauthorized', { status: 401 });
    }

    // User can only access their sandbox
    const sandbox = getSandbox(env.Sandbox, userId);
    return Response.json({ authorized: true });
  }
};

プレビュー URL

プレビュー URL にはランダム生成のトークンが含まれます。URL を知っている人は、そのサービスにアクセスできます。

アクセスを取り消すには、ポートの公開を解除します。

await sandbox.unexposePort(8080);

クイックトンネル URL

クイックトンネル(sandbox.tunnels.get(port))は、Cloudflare が割り当てるランダムなホスト名の *.trycloudflare.com URL を返します。別のアクセストークンはありません。ホスト名そのものがアクセス制御です。URL を知っている人は、そのサービスに到達できます。アクセスを取り消すには、トンネルを破棄します。

await sandbox.tunnels.destroy(8080);

URL はコンテナ再起動後に残りません。再起動すると、実質的にホスト名が入れ替わります。プレビュー URL と同様に、機密性の高いサービスにはアプリケーション層の認証を追加してください。詳細は Tunnels API を参照してください。

from flask import Flask, request, abort
import os

app = Flask(__name__)

def check_auth():
    token = request.headers.get('Authorization')
    if token != f"Bearer {os.environ['AUTH_TOKEN']}":
        abort(401)

@app.route('/api/data')
def get_data():
    check_auth()
    return {'data': 'protected'}

シークレットの管理

サンドボックスプロセスが直接使う値には、ハードコードしたシークレットではなく環境変数を使います。

// Bad - hardcoded in file
await sandbox.writeFile('/workspace/config.js', `
  const API_KEY = 'sk_live_abc123';
`);

// Good - use environment variables for values the sandbox process needs
await sandbox.startProcess('node app.js', {
  env: {
    API_KEY: env.API_KEY,  // From Worker environment binding
  }
});

サンドボックスが直接読む必要のない外部 API の認証情報は、Worker 側に置き、アウトバウンドハンドラーで注入します。

一時的な機密データは片付けます。

try {
  await sandbox.writeFile('/tmp/sensitive.txt', secretData);
  await sandbox.exec('python process.py /tmp/sensitive.txt');
} finally {
  await sandbox.deleteFile('/tmp/sensitive.txt');
}

アウトバウンドトラフィックを処理する

外部 API の認証情報を、環境変数やファイルでサンドボックスへ直接渡すと、サンドボックスプロセスが生きた認証情報を持ちます。内部で動くコードは、その値を読めます。アウトバウンドハンドラーは、認証情報を Worker 側に置き、送信リクエストへ注入することで、この露出をなくします。

流れは次のとおりです。

Sandbox request → Outbound handler (injects real credentials) → External API

サンドボックスは本物の認証情報を見ません。Worker の環境でシークレットをローテーションすると、以降のリクエストは更新後の値を使います。

このパターンは、プライベートリポジトリ操作用の GitHub、AI サービス、オブジェクトストレージなど、認証情報をコンテナの外に置きたいときに有効です。実装の詳細は アウトバウンドトラフィックを処理する を参照してください。

SDK が防ぐもの

  • サンドボックス間のアクセス(VM 分離)
  • リソース枯渇(適用されるクォータ)
  • コンテナエスケープ(VM ベースの分離)

実装が必要なもの

  • 認証と認可
  • 入力の検証とサニタイズ
  • レート制限
  • アプリケーション層のセキュリティ(SQL インジェクション、XSS など)

ベストプラクティス

分離には別のサンドボックスを使う:

const sandbox = getSandbox(env.Sandbox, `user-${userId}`);

入力はすべて検証する:

const safe = input.replace(/[^a-zA-Z0-9._-]/g, '');
await sandbox.exec(`command ${safe}`);

シークレットには環境変数を使う:

await sandbox.startProcess('node app.js', {
  env: { API_KEY: env.API_KEY }
});

一時リソースを片付ける:

try {
  const sandbox = getSandbox(env.Sandbox, sessionId);
  await sandbox.exec('npm test');
} finally {
  await sandbox.destroy();
}

関連リソース

役に立ちましたか?