TL

CORS(オリジン間リソース共有)

別オリジンのデータを fetch すると出る、あの赤いエラーの正体。ブラウザの安全装置(同一オリジンポリシー)を、サーバ側のヘッダで“例外的に許可”する仕組み。

中級CORSWebセキュリティブラウザ最終更新: 2026-06-04
TL;DR要点だけ先に
  • 1.CORS は「別オリジンへのアクセスをサーバが許可する」仕組み。判定して許可を出すのはブラウザ+サーバで、フロントのコードでは消せない。
  • 2.鍵は HTTP レスポンスの Access-Control-Allow-Origin ヘッダ。これが無い/合わないとブラウザがレスポンスを読ませず、エラーになる。
  • 3.PUT や独自ヘッダなど“危ない”リクエストは、本番の前に OPTIONS(プリフライト)で「送っていい?」と事前確認が走る。

ポイントは、CORS はサーバのアクセスを増やす緩和策であって、制限を強める仕組みではないこと。そして判定するのはブラウザだということです。だから「JS のコードを直せば直る」ものではありません。

オリジンとは(scheme / host / port)

「オリジン(origin)」は、URL のうち スキーム・ホスト・ポートの3点セットを指します。この3つがすべて一致して初めて「同一オリジン」です。

https://example.com:443/page を基準にすると…

相手の URL同一オリジン?理由
https://example.com/other✅ 同一scheme/host/port が一致(443 は https の既定)
http://example.com/❌ 別オリジンscheme が http で違う
https://api.example.com/❌ 別オリジンhost(サブドメイン)が違う
https://example.com:8443/❌ 別オリジンport が違う
パスやクエリは関係ない

オリジンの判定にパス・クエリ・フラグメントは含みません/a/b は同一オリジン。逆に httphttps の違い、example.comwww.example.com の違いは別オリジン扱いです。ここを取り違えると、なぜCORSが出るのか分からなくなります。

同一オリジンポリシーと、なぜ CORS が要る

ブラウザには 同一オリジンポリシー(Same-Origin Policy) という安全装置があります。あるオリジンの JavaScript が、別オリジンのレスポンスの中身を勝手に読むことを禁じるルールです。

なぜ必要か。もし制限が無ければ、あなたが開いている悪意あるサイトの JS が、裏で https://bank.example.com/balanceあなたのログイン状態(Cookie)込みで叩き、残高を読み取って盗み出せてしまいます。これを防ぐのが同一オリジンポリシーです。

一方で現実には、https://app.example.com のフロントが https://api.example.com の API を呼ぶ、といった正当な別オリジン通信が必要です。そこで「サーバ側が明示的に許可したものだけ通す」仕組みとして CORS が用意されています。

“ブロック”されても通信自体は飛んでいることが多い

よくある誤解です。単純リクエストの場合、ブラウザはリクエスト自体はサーバに送っています。サーバの処理(DB更新など)は走り得ます。ブラウザがやっているのは「許可ヘッダが無いレスポンスを、JS に読ませない」こと。だから CORS は“盗み見の防止”であって、“サーバへの到達の防止”ではありません(プリフライトが付く場合は事前に止まります)。

単純リクエストとプリフライト

CORS には大きく2パターンあります。リクエストが「単純(simple)」かどうかで分岐します。

単純リクエストの主な条件(ざっくり):

  • メソッドが GET / POST / HEAD のいずれか
  • 独自ヘッダを付けない(Authorization など追加のものは原則NG)
  • Content-Typeapplication/x-www-form-urlencoded / multipart/form-data / text/plain のいずれか

これらを1つでも外れると「単純でない」とみなされ、本番リクエストの前に プリフライト(preflight) が走ります。プリフライトは OPTIONS メソッドで「これから本番を送りたい。許可する?」とサーバに事前確認する仕組みです。

観点単純リクエストプリフライトを伴うリクエスト
きっかけGET/POST 等+安全なヘッダのみPUT/DELETE、独自ヘッダ、application/json など
往復回数本番1回のみOPTIONS(事前確認)→ 本番 の2回
事前確認なし(いきなり本番)OPTIONS でサーバの許可を確認してから本番
副作用本番が即サーバに届く許可されなければ本番は送られない
JSON を POST すると単純じゃなくなる

モダンな API でありがちな Content-Type: application/jsonPOST は、単純リクエストの条件を外れます。結果、必ずプリフライト(OPTIONS)が先に飛びます。「GET は通るのに POST だけ落ちる」と感じたら、まず OPTIONS が許可されているかを疑いましょう。

Access-Control-Allow-* ヘッダ

許可を出すのはサーバのレスポンスヘッダです。代表的なものを押さえれば全体像がつかめます。

ヘッダ付ける場所意味
Access-Control-Allow-Origin本番+OPTIONSどのオリジンを許可するか(例: https://app.example.com / *)
Access-Control-Allow-MethodsOPTIONS の応答許可するメソッド(GET, POST, PUT…)
Access-Control-Allow-HeadersOPTIONS の応答許可する独自ヘッダ(Authorization, Content-Type…)
Access-Control-Allow-Credentials本番+OPTIONSCookie 等の資格情報付きを許可するか(true)
Access-Control-Max-AgeOPTIONS の応答プリフライト結果をキャッシュする秒数

プリフライトでは、ブラウザが Access-Control-Request-Method / Access-Control-Request-Headers で「こういう本番を送りたい」と申告し、サーバが上記の Allow-* で「OK / NG」を返す、という対話になっています。

ワイルドカード * と Cookie は併用できない

資格情報(Cookie やクライアント証明書)を送る場合、Access-Control-Allow-Origin: *使えません。許可オリジンを https://app.example.com のように具体名で明記し、かつ Access-Control-Allow-Credentials: true が必要です。さらにフロント側も fetch(url, { credentials: "include" }) のように資格情報送信を指定します。ここは仕様で固められたセキュリティ要件で、抜け道はありません。

典型的なエラーと対処

ブラウザのコンソールに出る代表的なメッセージと、原因の切り分けです。

症状(コンソール)本当の原因対処
No 'Access-Control-Allow-Origin' header is presentサーバが許可ヘッダを返していないサーバ側で対象オリジンに Allow-Origin を付与
does not match (Origin が許可リストに無い)Allow-Origin の値が呼び出し元と不一致許可オリジンに自分の origin を追加(http/https・サブドメイン注意)
Response to preflight... 403/404OPTIONS をサーバが処理していないOPTIONS ルートを実装し 2xx+Allow-* を返す
credentials... wildcard not allowed* と Cookie を併用しているオリジンを具体名にし Allow-Credentials: true を返す
“フロントだけ”で直そうとしない

CORS はブラウザがサーバの許可を確認する仕組みなので、原則としてサーバ側のヘッダ設定で直すものです。フロントの mode: 'no-cors' は一見回避策に見えますが、レスポンスの中身を読めなくなる(opaque になる)ため、API 呼び出しの解決策にはなりません。どうしてもサーバを直せない時の最終手段が、自前のバックエンド経由で中継するプロキシです(ブラウザを介さないサーバ間通信に CORS は適用されないため)。

例:許可するサーバと、呼ぶ側

サーバが返すべきレスポンスヘッダ(イメージ)。

HTTP/1.1 200 OK
Access-Control-Allow-Origin: https://app.example.com
Access-Control-Allow-Methods: GET, POST, PUT, DELETE
Access-Control-Allow-Headers: Content-Type, Authorization
Access-Control-Allow-Credentials: true
Access-Control-Max-Age: 600
Content-Type: application/json

プリフライトが走るときの、ブラウザ → サーバの OPTIONS(イメージ)。

OPTIONS /items HTTP/1.1
Origin: https://app.example.com
Access-Control-Request-Method: PUT
Access-Control-Request-Headers: Content-Type, Authorization

呼ぶ側の JavaScript。Cookie を送るなら credentials の指定を忘れずに。

// JSON の PUT → 自動でプリフライト(OPTIONS)が先に飛ぶ
const res = await fetch("https://api.example.com/items/1", {
  method: "PUT",
  headers: { "Content-Type": "application/json" },
  credentials: "include", // Cookie 等を送る場合
  body: JSON.stringify({ name: "demo" }),
});
const data = await res.json();

CORS はあくまでブラウザの世界の話です。土台となる HTTP の仕組みは HTTP / HTTPS を、ブラウザから API を叩く側の作法は REST API もあわせてどうぞ。

Web/フロントエンド Article

CORS(オリジン間リソース共有)を実務で読む

TL;DRは入口です。実際に選ぶ・使う段階では、何を解決するか、何と比較するか、導入後にどこで詰まるかまで見る必要があります。

解決すること

CORS

比較で見る軸

難易度: intermediate / カテゴリ: Web/フロントエンド / タグ数: 4

導入後に効く点

鍵は HTTP レスポンスの Access-Control-Allow-Origin ヘッダ。これが無い/合わないとブラウザがレスポンスを読ませず、エラーになる。

先に潰すリスク

用語だけ覚えても、設計・実装・運用でどこに効くかを確認しないと判断を誤る。

数字・仕様の読み方
難易度
intermediate
カテゴリ
Web/フロントエンド
タグ数
4

判断チェックリスト

  • 自社の用途が「CORS / Web」に近いか確認する。
  • 強みである「CORS は「別オリジンへのアクセスをサーバが許可する」仕組み。判定して許可を出すのはブラウザ+サーバで、フロントのコードでは消せない。」が本当に評価軸になるか確認する。
  • 注意点の「用語だけ覚えても、設計・実装・運用でどこに効くかを確認しないと判断を誤る。」を運用で吸収できるか確認する。
  • 公開値や仕様値は、対象プラン・対象機種・対象リージョンまで確認する。
  • 既存システム、ID、ネットワーク、監視、バックアップとの接続方法を先に洗い出す。
  • 小さく試してから、本番移行、権限設計、障害時手順、コスト監視を決める。

次に確認する観点

CORSWebセキュリティブラウザCORSWebセキュリティブラウザ
参考: 公式情報