先に読むと理解しやすい記事:HTTP・HTTPS / URL・ドメイン・オリジン / 同一オリジンポリシー(SOP)
CORSは別オリジンのコードへ応答を渡す許可
CORSはCross-Origin Resource Sharingの略です。あるオリジンのページで動くJavaScriptが別オリジンのサーバーを呼ぶとき、その応答をコードへ渡してよいか、サーバーの許可を使ってブラウザが判断する仕組みです。
たとえば https://app.example の画面が https://api.example の商品一覧を取得する構成を考えます。APIが画面のオリジンを許可するヘッダーを応答に付けると、ブラウザは許可を確認して商品データを画面のコードへ渡します。許可しない場合、リクエストが届いてもコードは応答を読めないことがあります。
参照:出典 s1
Originはブラウザが示し、許可はAPIが返す
Originは呼び出し元のオリジンを示すリクエストヘッダーです。通常のブラウザのJavaScriptが任意の値へ自由に書き換えるヘッダーではありません。APIはこの値を許可リストと比べ、許可する場合にAccess-Control-Allow-Originを応答へ付けます。
次の例は公開の商品一覧です。許可値はURLのパスを含まないオリジンで、一つの値です。複数の候補をカンマで並べる設定ではありません。呼び出し元ごとに許可値を変え、応答を共有キャッシュへ保存するなら、Origin別に応答を区別するVary: Originも必要になります。
説明用の通信例・設定例・擬似コード
GET /products HTTP/1.1
Host: api.example
Origin: https://app.example
HTTP/1.1 200 OK
Access-Control-Allow-Origin: https://app.example
Vary: Origin
Content-Type: application/json
[{"name":"Notebook"}]プリフライトは本来のリクエストを送る前の確認
別オリジンへのPUTやDELETEでは、ブラウザは通常、先にOPTIONSで許可を確認します。Content-Typeがapplication/jsonの場合や、Authorizationヘッダーを付ける場合も、この事前確認の対象です。この事前確認をプリフライトと呼びます。既に有効な確認結果がキャッシュされていれば、省略される場合があります。
ブラウザは予定しているメソッドをAccess-Control-Request-Method、対象ヘッダー名をAccess-Control-Request-Headersで伝えます。APIがAccess-Control-Allow-MethodsとAccess-Control-Allow-Headersなどで許可すると、ブラウザは本来のリクエストを送ります。本来のレスポンスにも必要なCORS許可が必要です。
通常のプリフライト自体にはCookieなどの資格情報を付けません。APIがOPTIONSにもログインを必須にすると、正規の画面から本来の通信を始められなくなることがあります。OPTIONSの許可は、実際の更新処理の認証・認可を省いてよいという意味ではありません。
説明用の通信例・設定例・擬似コード
OPTIONS /profile HTTP/1.1
Host: api.example
Origin: https://app.example
Access-Control-Request-Method: PUT
Access-Control-Request-Headers: content-type
HTTP/1.1 204 No Content
Access-Control-Allow-Origin: https://app.example
Access-Control-Allow-Methods: PUT
Access-Control-Allow-Headers: content-typeフォーム相当の送信は事前確認なしで届き得る
GET・HEAD・POSTで、ヘッダーや本文形式などが一定の条件を満たす場合、ブラウザはプリフライトをせずに本来のリクエストを送ります。たとえば通常のフォームに近いapplication/x-www-form-urlencodedのPOSTは、この対象になり得ます。
そのため、CORSの許可がないという理由だけで、別サイトからの更新操作を防いだとは言えません。サーバーがフォームを受け取って処理した後、ブラウザが応答の読み取りだけを禁止する場合があります。更新APIではCSRFトークンや送信元の検証も設計します。
Cookie付き通信は送信と読み取りの両方に条件がある
別オリジンへのfetchでCookieを送る構成では、画面側はcredentials: "include"を指定します。ただし、それだけで必ずCookieが送られるわけではありません。CookieのDomain・Path・Secure・SameSiteや、ブラウザの第三者Cookie制限などにも従います。
Cookie付きの応答を画面へ渡すには、API側がAccess-Control-Allow-Credentials: trueを返します。Access-Control-Allow-Originには、許可するオリジンを明記します。この場合に * は使えません。Cookieはブラウザが管理し、JavaScriptへSet-Cookieヘッダーを読ませることもありません。
説明用の通信例・設定例・擬似コード
// 正規画面 https://app.example からの説明用コード
fetch("https://api.example/profile", { credentials: "include" });
// APIのレスポンスヘッダー例
Access-Control-Allow-Origin: https://app.example
Access-Control-Allow-Credentials: true
Vary: Origin送られたOriginをそのまま許可すると何が起きるか
次は設定不備を説明する仮定です。APIが、受け取ったOriginを確認せず許可値へコピーし、Cookie付き読み取りも許可するとします。攻撃者は自分のサイトのJavaScriptから、credentials: "include"を指定して被害者のプロフィールAPIを呼びます。
被害者がログイン中で、その通信にログイン用Cookieが送られる条件も満たすと、APIは被害者の住所などを返します。APIが攻撃者のオリジンを許可したため、ブラウザは応答を攻撃者のコードへ渡します。そのコードが住所を攻撃者の収集先へ送れば、攻撃者が取得できます。Cookieが送られない環境まで、この経路が成立すると断定はできません。
対策は、許可する画面のオリジンを固定の許可リストで照合することです。公開データへ * を指定する判断と、個人情報へ任意のOriginを反射する判断は区別します。
参照:出典 s1
CORSエラーは許可ヘッダーと実際の通信で調べる
開発者ツールで、Origin、本来のメソッド、OPTIONSの有無、APIが返した許可ヘッダーを確認します。エラー応答にも必要な許可がないと、画面からは元の401や500の本文を読めず、CORSエラーとして見えることがあります。
mode: "no-cors"を指定しても、任意のAPI応答が読めるようにはなりません。応答の内容をJavaScriptから参照できない制限付きの状態になります。
確認問題:APIキーを持たない外部プログラムをCORSで拒否できるでしょうか。答えはできません。CORSはブラウザの応答公開を制御する仕組みなので、API自身で認証・認可を実施します。
参照:出典 s1
出典・確認範囲
- [s1] Cross-Origin Resource Sharing (CORS)MDN / 確認日 2026-11-03
- [s2] Fetch Standard — CORS protocolWHATWG / 確認日 2026-11-03
通信例・設定例・被害の例は、仕組みを理解するための仮定です。特定の製品で発生した事件を示すものではありません。ブラウザやサービス固有の設定は、利用する環境の公式資料でも確認してください。