何が起きるか

CORSは、別オリジンの応答をページのJavaScriptに読ませてよいか、ブラウザがAPIの許可ヘッダーで判断する仕組みです。オリジンはスキーム・ホスト・ポートの組です。CORS設定の不備では、APIが攻撃者のオリジンまで許可し、利用者向けの非公開情報を攻撃者のページへ渡してしまいます。

説明用に、利用者が顧客情報サービスへログイン中に攻撃者のページを開く場合を考えます。そのページのJavaScriptがAPIへcredentials: includeを指定したfetchを行い、ブラウザが保存したログイン用CookieをAPI宛てに送れる構成だとします。ブラウザはCookieをリクエストのCookieヘッダーへ付け、Originヘッダーへ攻撃者のオリジンを入れます。APIはCookieで利用者を特定し、氏名や住所を返します。その応答のAccess-Control-Allow-Originへ攻撃者のオリジン、Access-Control-Allow-Credentialsへtrueを指定すると、ブラウザは応答を攻撃者のJavaScriptへ渡します。コードが読んだ情報を攻撃者のサーバーへ送れれば、攻撃者が他人の情報を取得できます。

この例ではSameSite=None; SecureなどのCookie設定とブラウザのCookie制限が別サイトへの送信を許し、APIも資格情報付き読み取りを許すことが必要です。CORSの許可だけではCookieを送る条件やサーバーの認証を省略できません。

正常ならどう動くか

通常、別オリジンのAPIへJavaScriptからfetchしても、ブラウザはその応答を呼び出し元のコードへ渡しません。正規の連携先から使わせる場合、APIはOriginリクエストヘッダーで送信元を確認します。許可したオリジンだけをAccess-Control-Allow-Originへ入れて応答します。ブラウザはこの値とページのオリジンを照合して読み取りを許可します。

Cookieなどの資格情報を伴う別オリジンのfetchでは、呼び出すコードがcredentials: includeを指定します。APIもAccess-Control-Allow-Credentials: trueを返す必要があります。Cookieの対象ホストやSameSite、ブラウザの送信制限も満たした場合だけ、CookieがAPIへのリクエストへ付きます。必要に応じて送られる事前のOPTIONSリクエストは、送信元やメソッド・ヘッダーを許可するか確認するプリフライトで、その許可も必要です。 たとえば独自ヘッダーを付けない通常のGETなら、Cookie付きという理由だけでプリフライトは発生しません。独自ヘッダーを付ける場合などは、ブラウザがOPTIONSを送り、APIの応答がそのオリジン・メソッド・ヘッダーを許可したと確認してから本来のリクエストを送ります。

不備と攻撃が成立する流れ

説明用の例として、被害者がログイン中の顧客情報APIを考えます。攻撃者は自分のサイトに、資格情報付きでそのAPIへfetchするJavaScriptを置き、被害者にページを開かせます。ブラウザはAPI宛てのHTTPリクエストのOriginヘッダーに、攻撃者のページのオリジンを設定します。Cookieの送信条件も満たせば、API向けのCookieをそのリクエストのCookieヘッダーに付けます。

APIがOriginの値を検査せずAccess-Control-Allow-Originへ写し、Access-Control-Allow-Credentialsもtrueで返すと問題になります。認証情報の送信などの条件を満たす場合、ブラウザは本人向けのレスポンスを攻撃者のページのJavaScriptへ渡します。サーバーが攻撃者のオリジンを信頼できる読み取り先として許可する処理が不備です。

CookieのSameSite属性や第三者Cookieの制限によって、資格情報付きリクエストが成立しない場合があります。プリフライトが必要な形式では、その確認でも許可されることが必要です。CORSの許可ヘッダーがあるだけで、常に被害者のログイン情報が送信されるわけではありません。

起こり得る被害と条件

顧客情報の例では、APIが返した氏名・住所を攻撃者のページのJavaScriptが読み、その値を含むHTTPリクエストを攻撃者のサーバーへ送ります。送信が成立すれば、攻撃者は被害者本人向けの情報を入手します。認証済みのAPIレスポンスを読めることが、単なる外部ページの表示と異なる被害です。

被害者のブラウザだけが接続できる社内APIでも、接続・認証・CORSの許可が全て成立すれば、そのAPIの応答を外部ページが読める場合があります。例えば内部の設定を返すAPIなら、その応答内容の漏えいが問題になります。ブラウザからの到達性や追加のアクセス制限に依存し、サーバーの全権限を得る攻撃ではありません。

防ぎ方と、防げる理由

APIはOriginのスキーム・ホスト・ポートの組全体を、設定した許可リストと照合します。一致した値だけをAccess-Control-Allow-Originへ出すため、攻撃者が勝手なOriginで要求しても、ブラウザは秘密の応答をそのページのJavaScriptへ渡しません。資格情報付き読み取りを許すAccess-Control-Allow-Credentialsは必要なAPIだけで有効にします。

送信元によって許可情報が変わる応答をキャッシュする場合は、Originごとに分けて保存・再利用します。たとえば共有キャッシュが連携先A向けのAccess-Control-Allow-Origin: Aを連携先Bへ返すと、Bのブラウザは値が一致せず、正規の連携でも読み取りに失敗します。異なる許可情報の使い回しを防ぐ運用上の対策で、それだけで秘密情報の読み取りが成功すると断定するものではありません。CORSを守るのはブラウザなので、攻撃者が直接APIへ接続するクライアントには認証・認可をサーバーで適用します。

よくある誤解

Access-Control-Allow-Originの*と資格情報付き読み取りを、そのまま併用できません。任意のOriginの値を、そのまま許可先として応答へ書き戻す設定は別です。また、CORSを厳しくしても、別サイトから送れる状態変更要求を使うCSRFがすべて防げるわけではありません。

実装の確認点

Originを部分一致や無条件の反映で許可していないか、nullを許可する必要があるかを確認します。資格情報付きfetchとCookieの送信条件、プリフライトと実際の応答の両方を調べます。許可された環境で、正規オリジンからは利用でき、信頼していないオリジンのJavaScriptからは秘密を含むレスポンスを読めないことを確認します。 Origin: nullはヘッダーの欠落とは別で、sandbox付きのiframeなど、送信元を通常のオリジンで表せないページから送られる値です。攻撃者もそのようなページを作れるため、nullを無条件で信用する設定を避けます。

出典・確認範囲

  1. [1] Web Security Academy: CORS設定の不備PortSwigger / 確認日 2026-11-01