MENU
スポンサーリンク
スポンサーリンク
スポンサーリンク

CORSとは何か?仕組みと役割をわかりやすく解説

当ページのリンクには広告が含まれています。
CORSとは何か?仕組みと役割をわかりやすく解説

「ローカルでは動くのに本番環境に出した途端CORSエラーでAPIが呼べなくなった」と画面のコンソールを見つめて固まってしまうことがあります。
別ドメインのバックエンドと通信したいのに「Access-Control-Allow-Originが〜」と英語のエラーが並び、どこを直せばいいのか判断しづらい状況もよく起こります。
この記事では、CORSという仕組みの全体像と基本用語を整理しながら、エラーに振り回されないための考え方を解説します。

この記事でわかること

・CORSの基本的な考え方とブラウザでの役割
・オリジンや同一オリジンポリシーなど前提となる概念
・プリフライトリクエストや主要CORSヘッダーの意味
・実務でCORSエラーに向き合うための判断基準と注意点

目次

CORSの基本と仕組みを整理する

まずはCORSがどんな問題を解決するための仕組みなのかを整理します。
ここを押さえておくと、ブラウザがなぜエラーを出しているのか、どの設定を変えるべきなのかを冷静に判断しやすくなります。
専門用語は一つずつ意味と役割をセットで見ていきます。

CORSの結論をざっくり3つにまとめる

CORSの全体像は次の三つにまとめられます。

  1. ブラウザには、別オリジンのリソースへのアクセスを制限する同一オリジンポリシーがある。
  2. サーバーはHTTPレスポンスヘッダーで「どのオリジンからなら読んでよいか」をブラウザに伝え、その制限を一部ゆるめられる。
  3. ブラウザはOriginヘッダーとAccess-Control系ヘッダーを読み、条件を満たさないレスポンスはJavaScriptから見えないようにする。

CORSは、HTTPヘッダーを使ってサーバーがどのオリジンからのリクエストを許可するかをブラウザーに伝える仕組みです。
(出典:MDN Web Docs) (MDN Web Docs)

ここで重要なのは、CORSが「ネットワークの通信自体を止めているわけではない」という点です。
多くの場合、リクエストとレスポンスはネットワーク的には成功していますが、ブラウザがセキュリティ上の理由でフロントエンドから結果を読めないようにしているだけです。

そもそもオリジンとは何か

CORSを理解するうえで、まず「オリジン」の意味を押さえる必要があります。
オリジンとは、URLのスキーム(プロトコル)+ホスト(ドメイン)+ポート番号の組み合わせで定義される単位です。
この三つがすべて同じなら同一オリジン、どれか一つでも違えば別オリジンとして扱われます。
(出典:MDN Web Docs 用語集 Origin) (MDN Web Docs)

例えば次の二つは同一オリジンです。

一方、次の組み合わせはどこかが違うため別オリジンになります。

現場では、SPAのフロントエンドを https://app.example.com、APIを https://api.example.com で提供する構成がよくあります。
この場合、サブドメインが異なるためクロスオリジンとなり、CORSのルールが関わってきます。

なぜブラウザにCORSが必要になったのか

もともとブラウザには、悪意のあるサイトがユーザーの別サイトの情報を勝手に読み取れないようにするための同一オリジンポリシーがあります。
これは「あるオリジンで動いているスクリプトから、別オリジンのコンテンツを自由に読み取れないようにする」セキュリティの仕組みです。

しかし、実務では「自社の別ドメインのAPIからデータを取得したい」「CDN上のライブラリを読み込みたい」といった正当なニーズも増えました。
そこで、例外的に他のオリジンのリソースを読めるようにする標準的な方法としてCORSが導入されました。

たとえるなら「建物ごとにセキュリティゲートを設けているが、特定の会社の社員証を持つ人だけは別棟にも入れるようにする」といったイメージです。
標準のセキュリティルールを壊すのではなく、「誰をどこまで通すか」をゲート側(サーバー)が明示する仕組みがCORSです。

プリフライトリクエストとシンプルリクエスト

CORSでは、すべてのクロスオリジンリクエストが同じ扱いになるわけではありません。
代表的な区別としてシンプルリクエストプリフライトが必要なリクエストがあります。

  • シンプルリクエスト
    • GETやPOSTなど一部のメソッド
    • 特定の範囲内のヘッダーとContent-Type
    • 条件を満たす場合は、追加の確認なしでそのまま本リクエストが送られる
  • プリフライトリクエスト
    • 本リクエストの前に、OPTIONSメソッドで「このメソッドとヘッダーを使うつもりだが許可されるか?」を問い合わせる
    • サーバーが応答ヘッダーで許可を示した場合のみ本リクエストが実行される

ブラウザは Origin ヘッダーを常に付与し、必要に応じて Access-Control-Request-MethodAccess-Control-Request-Headers を付けてサーバーに確認します。
サーバーはそれに対して Access-Control-Allow-OriginAccess-Control-Allow-Methods などで「何を許可するか」を返します。
(出典:MDN Web Docs CORS ガイド) (MDN Web Docs)

実務では、フロントエンドで独自ヘッダーを付けたり、JSON以外の特殊なContent-Typeを使ったりするとプリフライトが発生する場面がよくあります。
その際に、ネットワークタブを見るとOPTIONSリクエストだけが失敗している、といった症状がよく見られます。

CORSでよく登場する主要ヘッダー

CORSまわりで頻繁に目にするヘッダーの役割を整理します。

  • Origin
    • リクエストを送っている側のオリジンをブラウザが自動で付けるヘッダー
  • Access-Control-Allow-Origin
    • サーバー側が「どのオリジンからのアクセスを許可するか」を示す最重要ヘッダー
  • Access-Control-Allow-Methods
    • 許可するHTTPメソッドを列挙するヘッダー
  • Access-Control-Allow-Headers
    • 許可するリクエストヘッダーを列挙するヘッダー
  • Access-Control-Allow-Credentials
    • Cookieや認証ヘッダー付きのリクエストを許可するかどうかを示すヘッダー

とくに Access-Control-Allow-Origin は、どのオリジンのJavaScriptにレスポンスを読ませるかを決める中心的な役割を持ちます。
(出典:MDN Web Docs CORS 設定ガイド) (MDN Web Docs)

ここでよくある誤解として「ヘッダーを付ければどこからでもアクセスできて便利」という考え方があります。
実際には、許可範囲を広げるほど攻撃面も広がるため、必要なオリジンやメソッドだけを許可する慎重さが求められます。

例として、CDNで公開しているJavaScriptライブラリなど、どこから読まれても問題がないものについては Access-Control-Allow-Origin: * とするケースがあります。
一方で、ユーザーの認証情報を伴うAPIでは、特定のオリジンだけを厳密に指定するのが一般的です。

CORSエラーへの向き合い方と実務のポイント

実際に開発をしていると、ブラウザのコンソールにCORSエラーが表示されて手が止まってしまうことがあります。
ここでは、単に「ヘッダーを追加する」だけでなく、どこを見て何を判断すべきかという視点を整理します。
現場でよくあるケースを例に、落ち着いて切り分けるためのポイントを見ていきます。

実務でCORSを理解するための判断基準

CORSに関する問題が起きたとき、次のような順番で考えると整理しやすくなります。

  1. その通信は本当にブラウザからのJavaScript経由か
    • サーバーサイド同士の通信やバッチ処理であれば、CORSではなく別の問題である可能性が高いです。
  2. 通信相手は同一オリジンか別オリジンか
    • URLのスキーム、ホスト、ポートがすべて同じかどうかを確認します。
  3. CORSを設定すべきなのはどのサーバーか
    • 多くの場合、レスポンスを返す側のサーバーやリバースプロキシに設定が必要です。
  4. プリフライトが発生しているかどうか
    • ネットワークタブでOPTIONSリクエストの有無やステータスコードを見ると、どこで止まっているかが見えてきます。

フロントエンドとバックエンドの開発者が次のような会話をする場面はよくあります。

フロントエンド開発者「APIコールを追加したらCORSエラーになりました」
バックエンド開発者「ログには200で返っているけど、リバースプロキシでヘッダーが落ちていないか確認します」

このように、誰がどの位置でどのヘッダーを付与するかをすり合わせることが、CORS問題の解決では重要になります。

代表的なCORSエラーの読み解き方

ブラウザのコンソールには、いくつかパターン化されたCORSエラーが表示されます。
代表的なものとして、次のようなメッセージがあります。

  • No 'Access-Control-Allow-Origin' header is present on the requested resource
    • サーバーから必要な許可ヘッダーが返っていないケース
  • The value of the 'Access-Control-Allow-Origin' header in the response must not be the wildcard '*'
    • 資格情報付きのリクエストなのに、ワイルドカードが使われているケース
  • Response to preflight request doesn't pass access control check
    • プリフライトリクエストが許可されていない、もしくは失敗しているケース

これらのエラーメッセージは、どのヘッダーが足りないか、どの値が不適切かのヒントを含んでいます。
(出典:MDN Web Docs CORS のエラー) (MDN Web Docs)

現場では「とりあえず Access-Control-Allow-Origin: * を付けてみる」という対応をしがちですが、エラーの内容によっては根本的な解決にならない場合もあります。
エラー文を一つずつ読み解き、どの条件が満たされていないのかを確認する姿勢が大切です。

サーバー側で設定を変えるときの注意点

CORSの設定は、たいていサーバー側やAPIゲートウェイ、リバースプロキシで行います。
このとき、次のような点に注意する必要があります。

  • やみくもにワイルドカードを使わない
    • 認証付きAPIで Access-Control-Allow-Origin: * を使うと、意図しないサイトからのアクセスを許してしまう可能性があります。
  • オリジン単位で制御する設計を考える
    • 本番用フロントエンド、管理画面、開発環境など、必要なオリジンを洗い出して設定することが重要です。
  • CORSは認可や認証の代わりにはならない
    • CORSはあくまで「どのオリジンのスクリプトからレスポンスを読めるか」を制御する仕組みであり、ユーザーごとの権限管理とは別物です。

経験則として、CORSの設定を広げすぎると短期的には開発が楽になりますが、長期的にはセキュリティ上のリスクや意図しない依存関係を生みやすくなります。
「誰が、どの画面から、どのAPIに、どういう目的でアクセスするのか」という視点から、許可する範囲を決めると整理しやすくなります。

開発環境での一時的な回避方法の位置づけ

開発中は、次のような方法でCORS問題を一時的に回避することがあります。

  • ローカルのフロントエンド開発サーバーからバックエンドへのプロキシ設定を行う
  • ブラウザ拡張などで一時的にヘッダーを書き換える(本番では使用しない前提)
  • DockerやリバースプロキシでフロントとAPIを同一オリジンに見せかける

こうした方法は、あくまで開発効率を上げるための一時的な手段として位置づけることが重要です。
本番環境の構成とは別に、「ローカルではこうしているが、本番ではこのオリジンとこのオリジンを許可する」といった整理をドキュメント化しておくと、チーム内での認識のズレを減らせます。

よくある会話として、次のようなやりとりがあります。

フロントエンド開発者「ローカルでは開発サーバーのプロキシで動いていたのに、本番に出したらCORSエラーになりました」
バックエンド開発者「本番のフロントエンドのオリジンをCORSの設定に追加できていなかったので、オリジンの一覧を見直します」

このように、開発時の回避策と本番の正しい設定を切り離して考えることが、トラブルを防ぐポイントになります。

よくある質問

Q. サーバー側のログでは200なのに、フロント側ではCORSエラーになります。通信は成功しているのでしょうか。
A. 多くの場合、ネットワーク的には通信は成功しています。
ただし、CORSの条件を満たしていないため、ブラウザがセキュリティ上の理由でレスポンスの中身をJavaScriptから見えないようにしている状態です。

Q. CORSを設定すれば、CSRFなどの攻撃も防げますか。
A. CORSは「どのオリジンのスクリプトからレスポンスを読めるか」の制御が主目的です。
CSRF対策には、SameSite属性付きCookieやCSRFトークンなど、別の仕組みが必要になります。

Q. バックエンド同士の通信でもCORSエラーは起こりますか。
A. CORSはブラウザの仕組みなので、サーバー同士の通信やcurlによるリクエストでは通常関係しません。
その場合は、認証やネットワークの設定など、別の観点で問題を切り分ける必要があります。

Q. fetchでmodeを変えるとCORSエラーを回避できますか。
A. mode: "no-cors" などを指定すると表面的にはエラーが消える場合がありますが、レスポンスが「読めない」状態になることが多く、問題の本質的な解決にはなりません。
基本的にはサーバー側のCORS設定を適切に行うのが正しいアプローチです。

ブラウザのモダンなHTTP APIであるfetchは、デフォルトでCORSの仕組みと連携して動作するよう設計されています。
(出典:MDN Web Docs Using Fetch) (MDN Web Docs)

CORSの仕組みについてのまとめ

・CORSはブラウザとサーバーがヘッダーで対話する仕組み
・同一オリジンポリシーを部分的に緩和するための仕組み
・オリジンはスキームホストポートの組み合わせ
・CORSはJavaScriptからのクロスオリジン通信に適用される
・バックエンド同士の通信には通常CORSは関与しない
・シンプルリクエストはプリフライトが発生しない
・プリフライトは本番前に許可可否を問い合わせる事前確認
・Access Control Allow Originが許可オリジンを伝える
・資格情報を送るときはワイルドカード指定を避ける
・ブラウザはレスポンスヘッダーを見て結果をマスクする
・エラー文はどのヘッダーが足りないかのヒントになる
・原因の多くはサーバー設定かリバースプロキシの設定漏れ
・開発中の一時的な回避と本番設定は目的を分けて考える
・広く許可しすぎず必要なオリジンとメソッドだけを許可する
・仕様やブラウザ依存の挙動は公式ドキュメントで確認する

スポンサーリンク
スポンサーリンク
スポンサーリンク
よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!
目次