マガジン

別のドメインから配信される理由:投稿ゲームとメインサイトの分離

遊びを見つける

執筆にClaudeを使用しています。

小さなゲームの展示箱を、透明な仕切りと鍵で分けた模型。
記事のテーマをもとに制作したAI生成イメージ。実際のゲーム画面ではありません。

ゲームを1本アップロードして公開すると、そのゲームはアソバースの画面の中で遊べるようになります。ところが、ゲームのコードは作者が書いたものであり、メインサイトを作った側が中身をすべて読んで書いたものではありません。この「他人が書いたコードを、自分のサイトのページの中で動かす」という状況は、ブラウザの仕組みの上では慎重に扱う必要があります。 アソバースは、アップロードされたコードをメインサイトとは別のオリジンから配信し、さらにsandbox付きのiframeで実行しています。題名の問いに短く答えるなら、理由は「同じ敷地の中で、他人のコードにメインサイトの持ち物へ触れさせないため」です。住所(オリジン)が違えば、ブラウザは両者を別の持ち主として扱い、互いの中身を直接読ませません。 この記事では、オリジンとは何か、分離が何を守っているのか、分離したままセーブや記録がどう成り立つのかを、確認済みの事項だけを根拠に整理します。最後に、読者が自分のブラウザで分離を確かめる手順も示します。

この記事の目次
  1. オリジンとは何か:ブラウザが「持ち主」を見分ける単位
  2. メインサイトが持っているものと、ゲームに渡さないもの
  3. 二重の囲い:別オリジンとsandbox付きiframe
  4. 分離したまま、セーブはどう成り立つのか
  5. 自分のブラウザで分離を確かめる手順
  6. 次の行動
  7. 参考資料

オリジンとは何か:ブラウザが「持ち主」を見分ける単位

オリジンは、ページのURLのうち「スキーム(httpsなど)」「ホスト名」「ポート番号」の3つを合わせたものです。3つがすべて同じなら同一オリジンで、どれか1つでも違えば別オリジンになります。ブラウザには同一オリジンポリシーという基本ルールがあり、別オリジンのページ同士は、お互いの画面の中身や保存領域を直接読み書きできません。

次の表で、例として https://example.com を基準に比べてみます。

  • https://example.com/a と https://example.com/b、同一オリジンか:同一、違う要素:なし(パスは関係しません)
  • http://example.com、同一オリジンか:別、違う要素:スキーム
  • https://games.example.com、同一オリジンか:別、違う要素:ホスト名
  • https://example.com:8443、同一オリジンか:別、違う要素:ポート番号

注目したいのは、2行目から4行目のように「少し違うだけ」でも別オリジンとして扱われる点です。ホスト名の一部が共通していても、ブラウザにとっては別の持ち主です。

別オリジンになると、とくに次のものが分けられます。

  • ページのスクリプトから読める画面の中身(DOM)
  • localStorageやsessionStorageなどの保存領域
  • そのオリジンに対して送られるCookie

つまり、ゲームがメインサイトと別のオリジンで動いていれば、ゲームのコードはメインサイト側のページや保存領域を、ブラウザの標準ルールのもとでは直接読めません。仕組みの詳細はブラウザの公式資料で確認できます。

メインサイトが持っているものと、ゲームに渡さないもの

では、メインサイト側には何があるのでしょうか。アソバースでは、アカウントはGoogleまたはメールアドレスで作ります。ログイン中は、クラウドセーブ、作品ごとのプレイ履歴、あとで遊ぶ、好きな作品、作者のフォローなどが使えます。公開プロフィールの名前や紹介、レビュー、いいねもアカウントに結びついています。

これらはいずれも、遊ぶ人にとっては個人の記録です。アップロードされたゲームのコードがこれらに自由に触れられるとしたら、ゲームを開くたびに、作者が書いたコードに自分のアカウントの周辺を預けることになります。

この点について、設計から読み取れることがあります。確認済みの事項として、ゲームにはFirebaseのUID、認証トークン、メールアドレスを渡さないとされています。これは、分離が「ブラウザの標準ルールに任せる」だけでなく、ゲームへ受け渡す情報の側でも絞られていることを示しています。

まとめると、守りが2か所にあります。

  1. ブラウザの仕組み側:別オリジンなので、ゲームのコードはメインサイトのページや保存領域を直接読めません。
  2. 受け渡しの側:ゲームに渡す情報から、認証に使う情報やメールアドレスを外しています。

片方だけでも一定の効果はありますが、2か所に置くことで、どちらかの前提が崩れたときにも、もう一方が残ります。

二重の囲い:別オリジンとsandbox付きiframe

ゲームの実行方法についても、確認済みの事項があります。ゲームはsandbox付きのiframeで実行され、アップロードしたコードはメインサイトと別のオリジンから配信されます。ここでは役割の違う2つの囲いが重なっています。

  • 別オリジン配信:ブラウザが「持ち主が違う」と判断する、住所による区切りです。
  • sandbox付きiframe:ページの中に小さな部屋を作り、その部屋でできることを制限する仕組みです。どの操作を許すかは、iframeに付ける指定で決まります。

住所による区切りは「何を読めるか」の境界で、sandboxは「何をしてよいか」の境界です。役割が違うので、重ねる意味があります。

なお、sandboxの具体的な許可項目は、確認済みの事項には含まれていません。どの操作を許しているかをここで断定することはできません。気になる場合は、後半の手順で開発者ツールを使って、iframeに付いている指定を自分の目で見てみてください。

投稿方法による違いにも触れておきます。作品の投稿には、HTMLやZIPの直接アップロードと、公開済みURLの指定があります。「アップロードしたコードは別オリジンから配信」と確認されているのは前者です。公開済みURLで投稿されたゲームが、どのように読み込まれるかの細部は、この記事では断定しません。ただし、ゲームがsandbox付きiframeで実行される点は共通です。

分離したまま、セーブはどう成り立つのか

分離には代償もあります。メインサイトと切り離されたゲームは、ログイン中のアカウントを直接は知りません。それでも、アソバースにはクラウドセーブがあります。ここに分離の設計がよく表れています。

確認済みの事項を並べます。

  • アップロードしたゲームにはSDKが自動で追加されます。
  • URL投稿のゲームは、作者がSDKを読み込むと使えるようになります。
  • SDKを通じて、作品専用のプレイヤーIDとクラウドセーブが使えます。
  • クラウドセーブは作品ごとにJSONで128KiBまでです。
  • アップロード作品内のlocalStorageとsessionStorageは、一時メモリーとしての互換処理です。

ここから「設計から読み取れること」は次の3点です。

  1. ゲームが受け取るのは「作品専用のプレイヤーID」であり、アカウントそのものを示す情報ではありません。作品が違えばIDも別なので、ゲームの側から作品をまたいで同じ人を結びつける用途には向かない形です。
  2. 保存はゲームが自由に外部へ送るのではなく、SDKという決まった窓口を通ります。128KiBという上限や、JSONという形式も、その窓口で決まっています。
  3. localStorageなどが「一時メモリーの互換処理」とされているのは、ブラウザの保存領域に頼らず、記録はSDK経由のセーブに寄せる、という方針に沿った扱いと読めます。ただし、その理由が何かまでは確認済みの事項にありません。

公式作品13本のうち、保存があるのは「余白の庭」「WAVE / WAVE」「かたちのあいだ」の3作品で、他の10作品の記録や録音は画面を開いている間だけ残ります。ゲームごとに保存の有無が違うのは、「保存を使うかどうか」が作品の側の設計判断だからです。自作ゲームで保存を使うときは、上限と形式を前提に、保存したい内容を小さくまとめておく必要があります。

また、ゲストの履歴や進行は端末内に保存され、ログイン後のアカウントへ自動では混ざらない、とも確認されています。遊ぶ側の注意点として、ログイン前に遊んだ記録とログイン後の記録が別物であることは覚えておくと安心です。

自分のブラウザで分離を確かめる手順

ここからは、読者が自分で行える確認です。結果をこの記事で断定することはしません。ご自身のブラウザで見えたものが答えです。確認は、自分が開いているページの範囲にとどめ、他のサイトに対して試すことは避けてください。

準備するもの

  • パソコンのブラウザ(開発者ツールが使えるもの)
  • アソバース上でいずれかの作品を開いたページ

手順

  1. メインサイトの作品ページを開き、アドレスバーのURLを確認します。ホスト名の部分をメモしておきます。
  2. 開発者ツール(多くのブラウザでF12キー)を開き、「要素」または「Elements」タブでiframe要素を探します。
  3. iframeの src 属性と sandbox 属性を確認します。src のホスト名が、手順1のメモと同じか違うかを書き留めます。
  4. 「コンソール」タブを開きます。実行する場所(コンテキスト)を選べる欄があるので、ゲームのフレームを選びます。
  5. 次のコードを貼り付けて実行します。
js
console.log("このフレームのオリジン:", location.origin);
try {
  console.log("親のURL:", window.parent.location.href);
} catch (e) {
  console.log("親は読めません:", e.name);
}
try {
  console.log("親の保存領域の件数:", window.parent.localStorage.length);
} catch (e) {
  console.log("親の保存領域は読めません:", e.name);
}

記録の取り方

記録は、次の3点を1回分として十分です。

  • メインサイトのホスト名と、iframeの src のホスト名(手順1と3)
  • コンソールに表示された location.origin の文字列
  • 2つのtry文それぞれで、値が出たか、エラー名が出たか

作品を変えても、構造は同じはずです。別の作品でもう1回ずつ確認すると、「作品ごとに共通か」がわかります。

結果の読み方

  • iframeの src のホスト名がメインサイトと異なり、親の情報を読もうとしてエラーになるなら、ブラウザが別オリジンとして分けていると読めます。
  • location.origin が null と表示される場合があります。sandboxの指定内容によっては、そう表示されることがあります。その場合も、メインサイトと同じ表示にならないことが確認の要点です。
  • 親の情報が読めてしまう場合は、まず下の「起こりやすい誤り」を確認してください。それでも読める場合は、現在の案内で確認する、または編集部に問い合わせるのが確実です。

起こりやすい誤り

  • コンソールの実行場所がメインページのままだと、window.parent は自分自身を指します。この状態では親の情報が読めますが、分離とは関係のない結果です。必ずゲームのフレームを選んでください。
  • ブラウザの拡張機能や開発者向けの設定が、表示に影響することがあります。迷ったら、拡張機能を切った状態で確かめ直してください。
  • エラー名は、ブラウザの種類によって表現が少し違うことがあります。名前の一致よりも、「読めたか、読めなかったか」で判断します。

次の行動

まず上の手順で、メインサイトとゲームのホスト名が違うことを、ご自身の画面で見てみてください。作る側の方は、保存したい内容が128KiBに収まるかを確かめたうえで、SDK経由のセーブを前提にゲームを設計してみてください。

参考資料

  • MDN Web Docs「同一オリジンポリシー」
  • MDN Web Docs「<iframe>:インラインフレーム要素(sandbox属性)」

出典・参考資料