---
type: explanation
title: Caputchin がゲームをどうサンドボックス化するか
summary: "Caputchin のゲームの周りのすべての隔離の手立て：不透明オリジンの iframe、その単一のサンドボックストークン、厳格なインライン Content-Security-Policy、完全性ハッシュ、そしてそのすべてが、あなた自身のページに設定する CSP とどう共存するか。"
---

Caputchin のゲームは、あなたの訪問者のブラウザで、あなたのページで走るサードパーティのコードです。マーケットプレイスから来ようと、あなた自身がホストしようと、Caputchin はそれを **既定で信頼されないもの** として扱い、いくつかの独立した隔離の層で包むので、バグのある、あるいは敵対的なゲームは、レンダリングし、遊び、結果を報告できますが、ほかには何にも到達できません。あなたのページにも、あなたの訪問者のデータにも、ネットワークにもです。

このページは、すべての手立て、それぞれがなぜ存在するか、そしてその全体が、あなた自身のサイトに加える CSP とどう相互作用するかを説明します。

## 一行での脅威モデル

ゲームは、サードパーティが供給する任意の JavaScript（そしておそらく WebAssembly）を走らせます。したがって隔離の目標は：**ゲームは計算と描画ができ、結果をウィジェットに渡し戻せるが、自身のフレームの外側の何も読んだり影響したりできない。** 以下のすべての層はその 1 つの目標に仕え、それらは多層防御で、どの単一の層も完璧だと信頼されません。

```mermaid
flowchart TD
  P["Your page (your origin)"] --> W["Caputchin widget (your origin)"]
  W -->|builds the iframe| F["Sandboxed iframe (null origin)"]
  F --> G["The game: JS / WASM"]
  G -->|postMessage result only| W
  subgraph Inside the frame
    G
    L1["sandbox=allow-scripts only"]
    L2["inline Content-Security-Policy"]
    L3["Subresource Integrity (marketplace)"]
  end
```

## 層 1：不透明オリジンのサンドボックス化された iframe

すべてのゲームは、ウィジェットが意図的に最小限の `sandbox` 属性で作る `<iframe>` の中で走ります。付与される **唯一の** トークンは `allow-scripts` です。ゲームは JavaScript で、走らなければならないからです。ほかのすべては差し控えられ、最も重要な省略は `allow-same-origin` です。

`allow-same-origin` がないと、ブラウザはフレームに一意の **null オリジン** を与えます。その 1 つの事実が、荷重を支える境界です：

- ゲームはあなたのページの DOM、クッキー、`localStorage`、または Caputchin のセッションを読めません。あなたのものとは異質な、使い捨てのオリジンに封じられています。
- フレームはまた、あなたのトップウィンドウをナビゲートしたり、ポップアップを開いたり、フォームを送信したり、ネイティブのダイアログを出したりも決してできない（それらの能力はすべて Caputchin が付与しないサンドボックストークンです）ので、ゲームからあなたのページへ戻るパスがありません。

**`allow-same-origin` なしの `allow-scripts`** の組み合わせが要点そのものです。ブラウザはゲームのコードを実行しますが、フレームを、あなたのものに何も触れられない異質なオリジンとして扱います。Caputchin はゲームのフレームに `allow-same-origin` を決して加えません。（結果として、ゲームがウィジェットにポストするすべてのメッセージはオリジン `"null"` から届き、ウィジェットのチャネルのチェックはそれを期待します。null でないオリジンは、それ自体が設定ミスのサンドボックスを示します。）

## 層 2：フレームのドキュメントは取得されず、インラインで作られる

ウィジェットは iframe をリモートのページに向けません。フレームの HTML ドキュメント全体を **インラインで**（`srcdoc` 経由で）構築し、それを null オリジンのフレームに渡します。そのドキュメントは小さいです。厳格な CSP の meta タグ（次の層）、小さな Caputchin ランタイムのブートストラップ、そしてゲームのバンドルを読み込む 1 つの `<script>` タグです。

これは両方の配信パスで同じ仕組みで、バンドルの URL だけが違います：

| ゲームのソース | インラインドキュメントのバンドル URL |
|---|---|
| マーケットプレイス（プラットフォームが解決） | Caputchin がマウント時に解決した、固定された完全性ハッシュ付きのバンドル URL。 |
| セルフホスト（あなたの `game-src`） | あなたが供給した URL。 |

ドキュメントはゲームではなくウィジェットによって作られるので、ゲームは CSP、ランタイム、フレームの構造を決して制御せず、読み込まれた後に自身のバンドルがすることだけを制御します。

## 層 3：マーケットプレイスのゲームの Subresource Integrity

Caputchin はマーケットプレイスのゲームを提供するとき、バンドルを不変のバージョンに固定し、その暗号ハッシュ（SHA-384）を記録します。バンドルを読み込む `<script>` タグは、そのハッシュを `crossorigin="anonymous"` 付きの `integrity` 属性として運ぶので、固定されたものと 1 バイトでも違えば、**ブラウザ自身** がバンドルの実行を拒みます。侵害された CDN は違うコードを差し替えられません。読み込みはフェイルクローズします。

セルフホストのゲームには、プラットフォームが主張するハッシュがありません（あなたが自分のバイトの信頼の根です）ので、`integrity` 属性はそのパスでは単に省かれます。マーケットプレイスのゲームの *結果* がどうサーバーで独立に再導出されるか、完全性とは別の保証については、[リプレイ契約](/docs/marketplace-game-development/replay-contract) を参照してください。

## 層 4：厳格なインライン Content-Security-Policy

インラインドキュメントはきつい `Content-Security-Policy` を運びます。フレームがすでに null オリジンでサンドボックス化されているにもかかわらず、CSP は読み込まれたコードができることをさらに制約します。既定ですべてを拒否し、最小限だけを再付与します：

| ディレクティブ | 値 | なぜ |
|---|---|---|
| `default-src` | `'none'` | 下で明示的に許可されないすべてを拒否。 |
| `script-src` | Caputchin 自身のインラインランタイムのハッシュ + ゲームバンドルのオリジン + `'wasm-unsafe-eval'` | Caputchin の正確なブートストラップ（`'unsafe-inline'` **ではなく** `sha256-` ハッシュで固定）とゲーム自身のバンドルだけを走らせる。`'wasm-unsafe-eval'` は、完全な `'unsafe-eval'` を付与せずに WASM エンジンがコンパイルできるようにする。 |
| `connect-src` | `'none'` | **持ち出し防止のディレクティブ。** ゲームはどこへも `fetch`、`XHR`、`WebSocket` を開く、ビーコンができません。ネットワークの送出は一切なし。 |
| `img-src` | `data:`（加えて、下記のスキンアセットのオリジン） | スプライトはインライン、または許可されたアセットのホストから。 |
| `media-src` | `data:`（加えて、下記のスキンアセットのオリジン） | 音声/動画はインライン、または許可されたアセットのホストから。 |
| `font-src` | `data:` | インラインのフォントのみ。 |
| `style-src` | `'unsafe-inline'` | ゲームはインラインのスタイルを設定する。外部のスタイルシートはなし。（スタイルは、スクリプトやネットワークのようにはデータを持ち出せません。） |

正味の効果：ゲームは走り、レンダリングし、SDK のブリッジを通じて結果を報告し、ほかには何にも、特にネットワークには到達できません。この CSP は Caputchin が設定し、あなたが設定するものではありません。ゲームがどれだけ閉じ込められているかを正確に理解できるよう、ここに挙げています。

### 顧客の設定がフレームの CSP を広げる唯一の場所

スキンは、画像や音声のフィールドを、あなた自身の CDN の絶対 URL に向けられます（[スキン](/docs/game-customization/skin) を参照）。それらのアセットがロックダウンされたフレームの中で読み込まれるよう、Caputchin は **それらの正確なアセットのオリジンだけ** をフレームの `img-src` / `media-src` に加え、ほかのどこにも加えません。`script-src` と `connect-src` は決して広げられないので、許可されたアセットのオリジンでさえ、コードを読み込んだりネットワークのチャネルを開いたりに使えません。これが、設定された値がフレームのポリシーに影響する、単一の狭い方法で、それでもアセットだけです。

## 層 5：一方向の結果チャネル

ゲームはあなたのページへの呼び出せる面を持ちません。外への唯一の道は SDK のブリッジです。ゲームは、その不透明な結果（そのトレース）を、あなたのオリジンに住むウィジェットへ `postMessage` する単一のメソッドを呼びます。ウィジェットが Caputchin の API と話すものです。ゲームは決してしません（できません。`connect-src` が `'none'` です）。なので信頼のパスは ゲーム → ウィジェット → あなたのバックエンド で、各ホップは結果を前へ渡すだけで、ゲームに後ろへの到達を決して付与しません。

## あなた自身のページに設定する CSP [#the-csp-you-set-on-your-own-page]

上の層は *ゲームからあなたとあなたの訪問者を* 守ります。あなた自身のページの Content-Security-Policy は、別の、補完的な制御です。それは *あらゆるものからあなたのページを* 守り、Caputchin は厳格なものの下で走るよう設計されています。Caputchin を埋め込むために CSP を緩める必要はありません。**ウィジェットが正当に使う少数のオリジンを許可** すればよいのです。

最小限、ウィジェットは次を要します：

| ディレクティブ | 許可 | なぜ |
|---|---|---|
| `script-src` | ウィジェットのスクリプトを読み込むオリジン、加えて `'unsafe-eval'` | `<caputchin-widget>` / `<caputchin-game>` を定義する `<script>`、あなたが選んだ [CDN](/docs/integration-guides/cdn)（jsDelivr、あなた自身のホスト、または `caputchin.com`）。`'unsafe-eval'` は [計測](/docs/understanding-caputchin/instrumentation) のチャレンジを走らせます。計測がオンの間は必須で、キーの [セキュリティ](/docs/site-keys/security) ページで計測をオフにすれば落とせます。 |
| `connect-src` | `https://verify.caputchin.com` | ウィジェットは、検証を用意して確認するために Caputchin の検証サービスを呼びます。この正確なオリジンを許可してください。ウィジェットを別の API ホストに向けるなら、代わりにそれを許可してください。 |
| `frame-src` | `https://caputchin.com` | ゲームの iframe を統べます。フレームはインラインの `srcdoc` ドキュメントを使うので、ブラウザはあなたの `frame-src` をそれに適用します。なのでここで Caputchin のオリジンを許可してください。 |
| `worker-src` | `blob:` | proof-of-work のソルバーは、`blob:` URL から作られた Web Worker の中で完全に走り、メインスレッドのフォールバックがないので、これは必須です。`worker-src` を省くと、ブラウザは `child-src`、それから `default-src` にフォールバックし、`default-src 'self'` だけでは `blob:` を許可しません。 |

任意で `script-src` に `'wasm-unsafe-eval'` を加えてください。それは proof-of-work のソルバーを高速な WebAssembly として走らせます。必須ではありません。なしでも、ソルバーはより遅い純粋な JavaScript の実装（なお Worker の中）にフォールバックします。

ページの CSP でゲーム自身のバンドルのオリジン（jsDelivr、ゲームの CDN、あなたの `game-src` のホスト）を許可する必要は **ありません**。そのバンドルは、上で述べたフレーム自身の CSP の下で、*サンドボックス化されたフレームの中で* 読み込まれ、あなたのページのポリシーの下ではありません。あなたのページは Caputchin をフレームに収めるだけで、Caputchin が中で走るものを閉じ込めます。

Caputchin の要素があなたの CSP の下で黙って読み込みに失敗したら、あなたのブラウザのコンソールがブロックされたディレクティブを名指します。それが名指すオリジンかキーワードをそのディレクティブに加えてください。厳格に始め、コンソールが求めるものちょうどを開いてください。`'unsafe-inline'` は決して要りません。worker には `blob:`（`worker-src`）が要り、計測がオンの間は `script-src` に `'unsafe-eval'` が要ります。`'unsafe-eval'` の要件は、キーの [セキュリティ](/docs/site-keys/security) ページで計測をオフにすれば消えます。`'wasm-unsafe-eval'` は任意です（proof-of-work のソルバーを速くします。さもなければ同じ Worker の中で JavaScript としてより遅く走ります）。

## なぜこれほど多くの層か

各層は、それ自体で意味のある境界でしょう。一緒だと、1 つの失敗が破れではないことを意味します。null オリジンだけですでにゲームをあなたのデータから壁で隔て、CSP だけですでにネットワークの送出を殺し、完全性だけですでに正確なバイトを固定します。Caputchin はそのすべてを走らせます。信頼されないサードパーティのコードは、まさに多層防御が元を取る場所だからです。

## あわせて読む

- [ゲームがどうボットに抵抗するか](/docs/understanding-caputchin/gaming-anti-cheat)：ゲームの完全性の、サーバー権威の側。
- [リプレイ契約](/docs/marketplace-game-development/replay-contract)：ゲームの結果がどうサーバー側で独立に再導出されるか。
- [セルフホストのゲームを作る](/docs/custom-game-development/self-hosted-game)：これらのサンドボックスが作者に課すバンドルの制約。
- [CDN からウィジェットを読み込む](/docs/integration-guides/cdn)：あなたのページの CSP が許可しなければならないスクリプトのオリジンを選ぶ。
