同一オリジンポリシーとサイト分離の信頼境界
ブラウザが守る信頼境界を一段深く理解。オリジンとサイトの違い、COOP/COEP/CORP の役割、crossOriginIsolated の意味を整理し、Spectre 時代の防御設計を正確に組めるようになります。
- 1.オリジンは scheme/host/port の3点組、サイトは scheme+eTLD+1(登録可能ドメイン)。SOP の単位はオリジンだが、プロセス分離やCookieの一部判定はサイト単位で動く。
- 2.SOP は既定の禁止、CORS はその緩和。逆に COOP/COEP/CORP はクロスオリジンの読み込み・参照を能動的に締める強化策で、目的が真逆。
- 3.COOP: same-origin と COEP: require-corp の両立で crossOriginIsolated=true になり、SharedArrayBuffer や高精度 performance.now() が解禁される。Spectre 対策が前提条件。
同一オリジンポリシー(SOP)は「別オリジンの中身を読ませない」既定ルールです。ただし現代のブラウザは、SOP だけでなくサイトという別の単位や、Spectre 以降に追加された一連のヘッダで信頼境界を多層化しています。ここを正確に区別できると、CORS・COOP・COEP の使い分けが一本の筋で見えてきます。
オリジンとサイトは別の単位
混同されがちですが、オリジン(origin) とサイト(site) は粒度が違います。
- オリジン:
scheme+host+portの3点組。SOP の基本単位。 - サイト:
scheme+ eTLD+1(登録可能ドメイン)。ポートは無視し、ホストは登録ドメインまで丸める。
eTLD は Public Suffix List(PSL)で定義される「実効トップレベルドメイン」で、.com や .co.jp、github.io などが該当します。eTLD+1 はそこにラベルを1つ足した、ユーザーが登録できる最小単位です。
| 2つの URL | 同一オリジン? | 同一サイト? |
|---|---|---|
| https://a.example.com と https://b.example.com | ❌ host が違う | ✅ eTLD+1 は example.com で一致 |
| https://example.com:443 と https://example.com:8443 | ❌ port が違う | ✅ port はサイト判定に無関係 |
| https://example.com と http://example.com | ❌ scheme が違う | ❌ scheme も含むため別サイト |
| https://foo.github.io と https://bar.github.io | ❌ host が違う | ❌ github.io が eTLD なので別サイト |
現在のサイト判定は scheme を含む「schemeful same-site」が標準です。http と https は同一サイトになりません。SameSite Cookie の判定もこの単位に従うため、混在環境では Cookie が送られず詰まることがあります。
なぜ2つの単位が要るのか。SOP は「JS がレスポンスを読めるか」というデータアクセスの境界、サイトは「ブラウザがどこまでをひとまとまりとして扱うか」という運用・分離の境界だからです。後述のサイト分離(プロセス割り当て)や一部の Cookie 属性はサイト単位で動きます。
SOP が守る境界と、CORS による緩和
SOP の核心は、あるオリジンの JavaScript に別オリジンのレスポンス本文を読ませないことです。<img> や <script>、<link> での読み込み自体は許す一方、fetch の結果や <canvas> に描いた他オリジン画像のピクセルなど「中身の読み取り」を封じます。これがないと、ログイン状態の Cookie を伴って他サイトの機密を盗み読みできてしまいます。
正当な別オリジン通信を通すための緩和策が CORS です。サーバーが Access-Control-Allow-Origin を返すことで、ブラウザが「このオリジンには読ませてよい」と判断します。判定するのはブラウザで、フロントのコードでは消せません。詳細は CORS(オリジン間リソース共有) を参照してください。
単純リクエストでは、ブラウザはリクエストを実際にサーバーへ送ります。SOP/CORS が止めるのは「レスポンスを JS に読ませる」段階であって、サーバー到達そのものではありません。状態を変える操作の防御は CSRF 対策(SameSite Cookie やトークン)の領分で、SOP とは別レイヤです。
サイト分離と Spectre — なぜ強化策が要るのか
CORS が緩和なら、COOP / COEP / CORP は逆向きの強化策です。背景には Spectre があります。Spectre は CPU の投機的実行を悪用し、同一プロセスのメモリを読み出すサイドチャネル攻撃です。つまり攻撃者のコードと機密データが同じプロセスに同居していること自体が危険になりました。
対策がサイト分離(Site Isolation) です。ブラウザは異なるサイトを別 OS プロセスに分け、クロスサイトのデータが同じアドレス空間に乗らないようにします。ここで分離の単位が「オリジン」ではなく「サイト」なのは、document.domain 操作など同一サイト内オリジン間の協調を壊さないための互換性配慮です。
ただしプロセス分離だけでは、SharedArrayBuffer のような高精度タイマーを構成できる機能を安全に提供できません。そこで「ページが自分のプロセスにクロスオリジンの汚染物を一切引き込んでいない」と保証するための仕組みが COOP/COEP です。
COOP / COEP / CORP の役割分担
3つのヘッダはレスポンスヘッダで、守る対象が異なります。
| ヘッダ | 守る対象 | 代表値と効果 |
|---|---|---|
| Cross-Origin-Opener-Policy (COOP) | window.opener 経由の参照 | same-origin で別オリジンとのブラウジングコンテキスト群を切断 |
| Cross-Origin-Embedder-Policy (COEP) | サブリソースの埋め込み | require-corp で、許可のないクロスオリジン読み込みを拒否 |
| Cross-Origin-Resource-Policy (CORP) | 自リソースが読まれる側 | same-origin / same-site / cross-origin で誰の埋め込みを許すか宣言 |
関係を整理すると、COEP は「読み込む側が、引き込むサブリソースに許可の証明を要求する」ポリシー、CORP は「読み込まれる側が、自分はどこに埋め込まれてよいかを宣言する」ポリシーです。COEP: require-corp 下では、各クロスオリジンサブリソースが Cross-Origin-Resource-Policy ヘッダ(または CORS)で明示的に許可を出していないと読み込めません。
HTTP/1.1 200 OK
Cross-Origin-Opener-Policy: same-origin
Cross-Origin-Embedder-Policy: require-corp
HTTP/1.1 200 OK
Cross-Origin-Resource-Policy: cross-origin
Content-Type: image/png
require-corp は全サブリソースに CORP/CORS を要求しますが、COEP: credentialless は資格情報(Cookie 等)を付けずに取得することで、CORP ヘッダを持たない他オリジンリソースも引き込めます。レガシーな画像配信などを壊さずに分離環境へ移行する緩衝材になります。
crossOriginIsolated が意味するもの
COOP: same-origin と COEP: require-corp(または credentialless)が両方成立すると、そのトップレベルドキュメントは「クロスオリジン分離(cross-origin isolated)」状態になり、self.crossOriginIsolated が true を返します。これは「このページのプロセスにはクロスオリジンの汚染物が混入していない」という保証です。
この状態が満たされて初めて、以下のような強力すぎて Spectre に悪用され得る機能が解禁されます。
| 解禁される機能 | なぜ分離が前提か |
|---|---|
| SharedArrayBuffer | 複数スレッドで共有メモリを直接読めるため、高精度タイマーを自作できてしまう |
| 高分解能の performance.now() | サイドチャネル攻撃には精密な時間計測が不可欠。非分離下では意図的に粗くされている |
| performance.measureUserAgentSpecificMemory() | プロセス内メモリ使用量の精緻な計測が漏えい経路になり得る |
つまり crossOriginIsolated は単なるフラグではなく、「サイドチャネルで隣を盗み見られないことをブラウザが確認した」という証明書です。WebAssembly のスレッド機能やマルチスレッド処理を本気で使うには、この分離が事実上の前提になります。Service Worker を絡めた高度なオフライン構成でも同じ制約が効くため、設計時には PWA と Service Worker の制約とあわせて検討するとよいでしょう。
COEP: require-corp を入れると、CORP も CORS も持たない他オリジンの画像・iframe・スクリプトが一斉に読めなくなります。広告・解析タグ・外部埋め込みが多いページでは破壊的変更になりがちです。本番投入前に Cross-Origin-Embedder-Policy-Report-Only でレポートを集め、影響範囲を測ってから切り替えるのが定石です。
まとめ — 3つの境界を重ねて読む
整理すると、ブラウザの信頼境界は層になっています。SOP が「データを読ませない」既定の壁、CORS がその穴を開ける緩和、COOP/COEP/CORP が「プロセスに他オリジンを混ぜない」強化、そして crossOriginIsolated がそれらの達成を示す到達点です。粒度の面では、SOP と CORS はオリジン、サイト分離と一部 Cookie 判定はサイトで動くことを押さえておくと、挙動の食い違いに迷いません。認証情報を伴う通信の落とし穴は Cookie とセッション管理 と Web 認証の仕組み もあわせてどうぞ。
Web/フロントエンド Article
同一オリジンポリシーとサイト分離の信頼境界を実務で読む
TL;DRは入口です。実際に選ぶ・使う段階では、何を解決するか、何と比較するか、導入後にどこで詰まるかまで見る必要があります。
解決すること
セキュリティ
比較で見る軸
難易度: advanced / カテゴリ: Web/フロントエンド / タグ数: 5
導入後に効く点
SOP は既定の禁止、CORS はその緩和。逆に COOP/COEP/CORP はクロスオリジンの読み込み・参照を能動的に締める強化策で、目的が真逆。
先に潰すリスク
用語だけ覚えても、設計・実装・運用でどこに効くかを確認しないと判断を誤る。
- 難易度
- advanced
- カテゴリ
- Web/フロントエンド
- タグ数
- 5
判断チェックリスト
- 自社の用途が「セキュリティ / Web」に近いか確認する。
- 強みである「オリジンは scheme/host/port の3点組、サイトは scheme+eTLD+1(登録可能ドメイン)。SOP の単位はオリジンだが、プロセス分離やCookieの一部判定はサイト単位で動く。」が本当に評価軸になるか確認する。
- 注意点の「用語だけ覚えても、設計・実装・運用でどこに効くかを確認しないと判断を誤る。」を運用で吸収できるか確認する。
- 公開値や仕様値は、対象プラン・対象機種・対象リージョンまで確認する。
- 既存システム、ID、ネットワーク、監視、バックアップとの接続方法を先に洗い出す。
- 小さく試してから、本番移行、権限設計、障害時手順、コスト監視を決める。