同一生成元ポリシー(SOP)徹底解説:定義・制約・実務対策と最新ヘッダ活用

同一生成元ポリシーとは

同一生成元ポリシー(Same-Origin Policy、SOP)は、ウェブブラウザが実装する重要なセキュリティ制約の一つで、ドキュメントやスクリプトが、どのリソースへアクセスできるかを「生成元(origin)」に基づいて制限する仕組みです。SOP はクロスサイトでの情報漏えいや不正操作を防ぐための基本的な防御層であり、ウェブの安全性を支える基盤技術になっています。

生成元(origin)の定義

「生成元」は通常、次の 3 要素の組み合わせで定義されます。

  • スキーム(例: http, https)
  • ホスト(例: example.com、IP アドレス)
  • ポート(明示的に指定されない場合はスキームの既定ポート)

したがって、https://www.example.com と http://www.example.com はスキームが異なるため別の生成元、https://sub.example.com と https://example.com はホストが異なるため別の生成元です(ポートも同様)。一部のスキーム(file:, data:, about: など)や blob URL はブラウザ実装上「不透明な(opaque)生成元」になる場合があり、通常の origin 比較とは扱いが異なります(仕様とブラウザ実装に注意が必要)。

なぜ重要なのか(SOP の狙い)

  • 別サイトのスクリプトが、ユーザーがログイン済みの別ドメイン上のページからデータを盗むことを防ぐ。
  • ローカルストレージやクッキー、DOM などの機密データが別生成元に勝手に参照・書き換えされるのを防止する。
  • XSS(クロスサイトスクリプティング)や CSRF(クロスサイトリクエストフォージェリ)といった攻撃の影響範囲を限定する基盤を提供する。

SOP による具体的な制約例

  • ドキュメント間の DOM アクセス:別生成元の iframe/ウィンドウの DOM を直接参照したり操作したりできない。
  • XMLHttpRequest / Fetch API:別生成元へのリクエスト自体は発行できるが(ブラウザは送信する)、レスポンスの読み取りは SOP により制限され、CORS で明示的に許可されていないと読み取れない。
  • ストレージ:localStorage、IndexedDB、Cookies(ドメインに基づく)は生成元スコープで分離される。
  • リソース読み込み:img、script、link 等でのリソース読み込みは多くの場合許可されるが、読み込んだコンテンツの「読み取り」や利用(例:Canvas に描画してピクセルを読み取る)は追加条件(CORS ヘッダなど)が必要になることがある)。

よく知られる回避手段と緩和方法

ウェブアプリで正当に別生成元間でデータをやり取りしたい場合はいくつか方法があります。重要なのは、ブラウザ側での明示的な許可(サーバー側設定や安全な API)を設けることです。

CORS(Cross-Origin Resource Sharing)

CORS は、サーバー側が HTTP ヘッダ(例:Access-Control-Allow-Origin)を返すことで、ブラウザに対して「この生成元からのスクリプトがレスポンスを読み取ってよい」と明示する仕組みです。典型的なポイント:

  • 単純リクエスト(simple request)はプリフライトなしで送信されるが、カスタムヘッダや特定のメソッドを使うとプリフライト(OPTIONS)が必要になる。
  • Access-Control-Allow-Origin にワイルドカード(*)を指定すると多くの場合便利だが、クッキー等の認証情報(credentials)を伴う要求の場合は使えない(ブラウザはワイルドカードと credentials=true の併用を許可しない)。
  • クッキーを含めたい場合は、サーバーは Access-Control-Allow-Credentials: true を返し、ブラウザ側で fetch の credentials: 'include'(あるいは XHR の withCredentials=true)を指定する必要がある。サーバーは具体的なオリジン(* ではない)を Access-Control-Allow-Origin に返す必要がある。

postMessage

window.postMessage API は、別生成元のウィンドウや iframe と安全にメッセージ交換を行うための標準的手段です。送信側は送るメッセージと許容するターゲットオリジンを指定し、受信側は event.origin をチェックして信頼できる送信元からのメッセージのみ処理します。これは DOM を直接触らずに限定的に通信するための推奨手段です。

document.domain(古い緩和手段)

同一オリジン内のサブドメイン間で緩和するために、同一のベースドメイン(例:example.com)に JavaScript から document.domain を設定して互いに同じ値にするとサブドメイン間でのアクセスが可能になることがあった。しかし制限が多く、パブリックサフィックス(co.uk 等)に対する制限やセキュリティおよび互換性の観点から推奨されず、現在は postMessage や CORS を使うのが一般的です。

JSONP(歴史的手段)

<script> タグは SOP による「レスポンス読み取り」制限を受けないため、過去には JSONP(スクリプトとしてサーバーから JS を返し、グローバル関数を呼ぶ)でクロスオリジンでデータ取得をしていました。しかし JSONP は CSRF のような攻撃面を生むため安全とは言えず、現在は CORS に置き換えられています。

関連する新しいヘッダと機能(COOP / COEP / CORP など)

近年、より厳格な分離や高級な機能(例:SharedArrayBuffer)の利用には、追加のクロスオリジン制御ヘッダが必要になっています。

  • Cross-Origin-Opener-Policy (COOP):ウィンドウ/プロセス分離を強化し、クロスオリジンからの参照や共有を制限する。ドキュメントを異なるプロセスに分離することでリスクを低減する。
  • Cross-Origin-Embedder-Policy (COEP):他オリジンの埋め込みリソースを明示的に制御(許可されている場合のみ埋め込める)し、安全な埋め込みのみを許可する。
  • Cross-Origin-Resource-Policy (CORP):リソース提供側が「このリソースはどのオリジンから埋め込めるか」を制御するためのヘッダ。

これらを組み合わせることで、ブラウザはより厳格なクロスオリジン分離を行い、安全な高機能 API の利用を可能にします。

実務上の注意点・よくある問題と対処

  • 「CORS エラー」がコンソールに出る場合:多くはサーバー側の Access-Control-* ヘッダ設定の問題。ワイルドカードと credentials の併用禁止や、プリフライトに対する正しい応答が返っていないことが原因。
  • 画像を Canvas に描画してからピクセルを読み取ろうとすると「tainted canvas」になる場合:画像側で適切な CORS ヘッダ(Access-Control-Allow-Origin)と、HTML 側で crossOrigin 属性が必要。
  • WebSocket:SOP が接続の発行を直接ブロックするわけではないが、ブラウザは Origin ヘッダを送るためサーバー側でチェックして接続を拒否できる。サーバー側にオリジン検査を実装するのが良い。
  • API 設計時は最小権限の原則で:必要最小限のオリジンだけを許可し、認証クッキーを扱う場合は credentials 周りを正しく設計する。
  • Legacy 手法(document.domain や JSONP)に依存しない:互換性やセキュリティの観点から現代的な手段(CORS, postMessage 等)に移行する。

攻撃ケースと SOP の限界

SOP は多くの攻撃に対して防御効果がありますが、万能ではありません。たとえば:

  • CSRF:SOP はクロスサイトでのリクエスト送信そのものを防がない(ブラウザはフォーム送信や画像読み込みなどを使って別オリジンに POST/GET を行える)。ただしレスポンスの読み取りは制限される。CSRF 対策(トークン、SameSite クッキー等)が別途必要です。
  • XSS:サイトが XSS を受けるとそのサイト内の機密情報を盗まれる。SOP はドメイン内での攻撃を止められないため、SOP は XSS による被害軽減には限界がある。

まとめ

同一生成元ポリシーはウェブの基本的なセキュリティモデルであり、生成元(scheme, host, port)の一致を基準に跨域アクセスを制限します。現実のアプリケーション開発では、CORS や postMessage、そして新しい COOP/COEP/CORP といったヘッダを適切に組み合わせることで、安全かつ柔軟に別生成元との通信を実現できます。サーバー側の設定ミスや legacy な回避策への依存が脆弱性を生むことが多いため、最新の仕様とブラウザ挙動を理解した上で実装することが重要です。

参考文献