結論(Cross-Origin-Opener-Policy)
Cross-Origin-Opener-Policy(COOP)とは、ページが別オリジンのウィンドウと「開いた側・開かれた側」の関係を共有するかを決めるレスポンスヘッダーです。この関係とは、window.opener や window.open() の戻り値による参照です。same-origin を指定すると別オリジンのページとは別のブラウジングコンテキストグループに分離され、相互にウィンドウを参照できなくなります。タブナビングやXS-Leaksを防ぎやすくし、クロスオリジン分離の前提条件の1つにもなります。
この記事のポイント
- 値は unsafe-none(既定)・same-origin-allow-popups・same-origin・noopener-allow-popups の4つです。
- 一般的な公開サイトは same-origin、外部の決済・認証ポップアップを使う場合は same-origin-allow-popups が目安です。
- 不正な値や二重付与(same-origin, same-origin)は unsafe-none として扱われ、保護が効きません。
- HTTPで配信されたページではブラウザはCOOPを無視します。
- セキュリティAIチェッカーは有効値を○、未設定・unsafe-noneを△、不正値を×、HTTP応答を対象外(重み1)とします。
| 診断項目名 | Cross-Origin-Opener-Policy |
|---|---|
| 項目ID | headers.coop |
| 分類 | セキュリティヘッダー |
| 重大度・配点の重み | 低(low) 重み 1 |
| 関連する標準・ガイドライン | OWASP ASVS 5.0.0 V3.4.8(文書を描画する HTTP 応答に、COOP の same-origin または same-origin-allow-popups を含める。Level 3)、HTML Standard(Cross-origin opener policies)、OWASP WSTG-CONF-14(Other HTTP Security Header Misconfigurations)、OWASP Secure Headers Project(推奨値 same-origin)、CWE-693(Protection Mechanism Failure) |
Cross-Origin-Opener-Policy(COOP)とは
**Cross-Origin-Opener-Policy(COOP)**とは、ページが別オリジンのウィンドウと「開いた側・開かれた側」の関係(window.opener や window.open() の戻り値)を共有するかどうかを決めるレスポンスヘッダーです。
Cross-Origin-Opener-Policy: same-origin
same-origin を指定すると、別オリジンのページとは別のブラウジングコンテキストグループに分離され、相互にウィンドウオブジェクトを参照できなくなります。これにより、外部サイトから公式サイトをポップアップで開いてウィンドウの状態を探る攻撃や、タブナビング(開かれた側から開いた側のページを偽サイトに差し替える攻撃)を防ぎやすくなります。
COOP は、SharedArrayBuffer などを使うための「クロスオリジン分離」の前提条件の1つでもあります。分離のもう1つの条件は「Cross-Origin-Embedder-Policy」で確認します。
COOPの値と仕組み
4つの値と動作
HTML Standard と MDN で定義されている値は次のとおりです。
| 値 | 動作 |
|---|---|
unsafe-none | 既定値。別オリジンの文書ともブラウジングコンテキストグループを共有できる |
same-origin-allow-popups | 自分が開いたポップアップのうち、COOP を設定していない(または unsafe-none の)ページへの参照は保持する。それ以外の別オリジンとは分離 |
same-origin | 同じ COOP を持つ同一オリジンの文書とだけグループを共有する。別オリジンとは完全に分離 |
noopener-allow-popups | 同一オリジンであっても、開いた側との関係を常に切る。比較的新しく追加された値 |
構文と、保護が無効になる書き方
COOP は Structured Fields のトークンとして解釈され、report-to パラメーターで違反レポートの送信先を指定できます。
Cross-Origin-Opener-Policy: same-origin; report-to="coop-endpoint"
HTML Standard では、値が不正だったり解析できなかったりした場合は unsafe-none として扱われる(fail open)と定義されています。注意したいのは次の点です。
- 同じヘッダーが2回送られて
same-origin, same-originのようなリストになった場合も解析に失敗し、保護は効きません。 - トークンは大文字小文字を区別するため、
Same-Originのような表記も無効です。 - HTTP で配信されたページ(非セキュアコンテキスト)では、ブラウザは COOP を無視します。
報告だけを行う Cross-Origin-Opener-Policy-Report-Only ヘッダーもあり、影響を確認してから本適用する段階導入に使えます。
COOPは何を防ぐか
- XS-Leaks(クロスサイトリーク):攻撃者のページが
window.open()で標的ページを開き、フレーム数(win.length)や遷移の有無などを観測して、ログイン状態や検索結果の有無などを推測する手法です。COOP で分離すると、攻撃者側の参照は切断されます。 - タブナビング:開かれたページが
window.opener.locationを書き換え、元のタブをフィッシングページに差し替える攻撃です。ASVS V3.4.8 は COOP がこれを防ぐと説明しています。 - Spectre 型サイドチャネル:別オリジンの文書を別プロセスに置くことで、メモリ読み取り型の攻撃の影響を減らします。
COOPについてよくある誤解
- 「
unsafe-noneを書けば設定済み」:unsafe-noneは既定値と同じで、分離の効果はありません。 - 「
same-originにすると外部リンクが開けなくなる」:通常のリンク遷移やtarget="_blank"は問題なく動きます。影響が出るのは、別オリジンのポップアップとの間でwindow.openerやpostMessageによるやり取りをしている場合です。 - 「COOP を付ければクロスオリジン分離になる」:分離には COEP(
require-corpかcredentialless)も必要です。COOP 単体でもポップアップ経由の攻撃対策としての効果があります。
Cross-Origin-Opener-Policyの診断基準(セキュリティAIチェッカー)
取得方法
- 入力URLへ GET を1回送り、リダイレクト(最大4回)後の最終応答の
Cross-Origin-Opener-Policyヘッダーを評価します。追加の通信はしません。 - 最終URLが HTTPS でない場合、ブラウザは COOP を無視するため、この項目は対象外とします。
- 値の前後の空白を除き、
;より前の部分(トークン)だけを取り出して、大文字小文字を区別して判定します。report-toなどのパラメーターは判定に影響しません。 Cross-Origin-Opener-Policy-Report-Onlyは評価対象外です(強制されないため)。
判定条件
| 判定 | 条件 | 得点への影響 |
|---|---|---|
| ○ 問題なし(pass) | トークンが same-origin、same-origin-allow-popups、noopener-allow-popups のいずれか | 重み1を満点加算 |
| △ 要確認(warn) | ヘッダーがない | 1×0.45=0.45点 |
| △ 要確認(warn) | トークンが unsafe-none(既定値と同じで分離効果なし) | 1×0.45=0.45点 |
| × 要改善(fail) | 上記以外の値(綴り誤り、大文字を含む表記、重複によるカンマ区切りリストなど)。ブラウザは unsafe-none として扱う | 0点 |
| 対象外(na) | 最終URLが HTTPS でない | 採点から除外 |
- 不正値を × とするのは、管理者が保護を意図して設定したのに実際には無効になっている状態で、未設定よりも気付きにくいためです。
- 根拠欄にはヘッダー値を表示し、
unsafe-noneの場合はその旨(既定値と同じで分離効果はないこと)を補足します。
自治体サイトでの判定例
| 応答ヘッダー | 判定 |
|---|---|
same-origin | ○ |
same-origin-allow-popups(外部の決済・認証ポップアップを使う電子申請) | ○ |
same-origin; report-to="coop" | ○ |
unsafe-none | △ |
| ヘッダーなし | △ |
same-origin, same-origin(Web サーバーと CMS で二重付与) | × |
sameorigin(綴り誤り) | × |
Same-Origin(大文字を含む) | × |
最終URLが http://(ヘッダーの有無によらない) | 対象外 |
COOPがないとどんなリスクがあるか
攻撃シナリオ
- タブナビングによるフィッシング:公式サイトから外部サイトへのリンクを住民がクリックし、新しいタブで開かれた外部ページ(改ざんされたもの、または悪意あるもの)が、元の公式サイトのタブを偽の「手続きページ」や「ログインページ」に書き換える。住民は元のタブに戻ったときに偽ページに入力してしまいます。COOP の分離と、外部リンクへの
rel="noopener"の付与(現在の主要ブラウザはtarget="_blank"に既定で noopener を適用)が対策になります。リンク側の対策は「別タブリンクのnoopener」で確認します。 - XS-Leaks による状態推測:攻撃者サイトが、職員用ポータルや住民マイページをポップアップで開き、ウィンドウの参照を通じてフレーム数や遷移を観測して、ログイン状態や特定の情報の有無を推測する。
- ポップアップ間の不正なメッセージ交換:ウィンドウ参照を保持したまま
postMessageを送り、受信側の送信元確認が不十分な場合に情報を引き出す。
想定される被害
- 住民の認証情報や個人情報の詐取(フィッシング)
- ログイン状態や利用状況などの推測によるプライバシー侵害
COOP 単体の欠如で直ちに被害が出るわけではないため重大度は low としていますが、ログイン機能や外部連携のあるサイトほど効果が大きくなります。
COOPの設定方法(Apache・nginx・IIS・Next.js)
値の選び方
| サイトの特徴 | 推奨値 |
|---|---|
| 一般的な公開情報サイト(外部ポップアップとの連携なし) | same-origin |
外部の決済、SNS ログイン、OAuth 認証などをポップアップで開き、結果を window.opener 経由で受け取る | same-origin-allow-popups |
他サイトからポップアップとして開かれ、window.opener で結果を返すページ(認証の戻り先など) | 設定前に動作確認が必要。same-origin にすると呼び出し元との連携が切れる |
Apache(.htaccess)
<IfModule mod_headers.c>
Header always set Cross-Origin-Opener-Policy "same-origin"
</IfModule>
nginx
add_header Cross-Origin-Opener-Policy "same-origin" always;
IIS(web.config)
<httpProtocol>
<customHeaders>
<add name="Cross-Origin-Opener-Policy" value="same-origin" />
</customHeaders>
</httpProtocol>
Next.js(Vercel)
// next.config.js
module.exports = {
async headers() {
return [{
source: "/:path*",
headers: [{ key: "Cross-Origin-Opener-Policy", value: "same-origin" }],
}];
},
};
Report-Onlyを使った段階的導入
- まず報告専用ヘッダーで影響を確認します。
Cross-Origin-Opener-Policy-Report-Only: same-origin; report-to="coop"
Reporting-Endpoints: coop="https://www.example.lg.jp/reports/coop"
- レポートや動作確認で問題がなければ、
Cross-Origin-Opener-Policyに切り替えます。 - 外部連携で問題が出たページは
same-origin-allow-popupsにするか、そのパスだけ別設定にします。
サイトを壊さないための注意点
- 電子申請・決済・外部認証:マイナンバーカードを使った認証や外部決済画面をポップアップで開き、完了後に元の画面へ結果を返す仕組みがある場合、
same-originで連携が切れることがあります。該当ページではsame-origin-allow-popupsを検討し、必ず実際の手続きを最後まで試してください。 - 二重付与の防止:Web サーバーと CMS(またはアプリ)の両方で付けると、値がカンマで連結されて解析に失敗し、保護が無効になります。付与箇所は1か所にします。
- iframe 内のページ:COOP はトップレベルの文書にだけ作用し、iframe 内の文書では無視されます。
設定後の確認方法
curl -sI https://www.example.lg.jp/ | grep -i cross-origin-opener-policy
ブラウザでは、開発者ツールの Application パネル(Frames の項目)で、トップフレームに適用された COOP を確認できます。外部サイトから window.open() で開いたときに戻り値の opener 関係が切れていることも確認できます。設定後はセキュリティAIチェッカーで再診断し、ヘッダー値が1つだけ返っていて ○ になることを確かめてください。
よくある質問(FAQ)
COOPをsame-originにすると外部リンクが開けなくなりますか?
通常のリンク遷移や target="_blank" は問題なく動きます。影響が出るのは、別オリジンのポップアップとの間で window.opener や postMessage によるやり取りをしている場合です。
COOPのsame-originとsame-origin-allow-popupsはどう使い分けますか?
外部ポップアップとの連携がない一般的な公開サイトは same-origin です。外部の決済、SNSログイン、OAuth認証などをポップアップで開き、結果を window.opener 経由で受け取る場合は same-origin-allow-popups を選びます。
Cross-Origin-Opener-Policy: unsafe-none と書けば設定済みになりますか?
なりません。unsafe-none は既定値と同じで、分離の効果はありません。セキュリティAIチェッカーでもヘッダーなしと同じ「△ 要確認」です。
COOPを付ければクロスオリジン分離(crossOriginIsolated)になりますか?
分離にはCOEP(require-corp か credentialless)も必要です。ただしCOOP単体でも、ポップアップ経由の攻撃への対策として効果があります。
COOPの値をSame-Originと大文字で書いても有効ですか?
無効です。トークンは大文字小文字を区別するため、Same-Origin はブラウザに unsafe-none として扱われます。セキュリティAIチェッカーでは「× 要改善」になります。
COOPを導入するとき、影響を事前に確認する方法はありますか?
Cross-Origin-Opener-Policy-Report-Only ヘッダーで報告だけを行い、レポートや動作確認で問題がなければ本適用に切り替えます。電子申請や外部認証などのポップアップ連携は、必ず手続きを最後まで試してください。
この項目を含む127項目を、URLを入れるだけで無料診断します。