Web セキュリティ

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

約 4 分で読めます

CORS (クロスオリジンリソース共有) とは

CORS (Cross-Origin Resource Sharing) とは、Web ブラウザの同一オリジンポリシーを安全に緩和し、異なるオリジン間でのリソース共有を可能にする HTTP ヘッダーベースの仕組みです。オリジンとは、スキーム (http/https)、ホスト名、ポート番号の 3 つの組み合わせで定義されます。

同一オリジンポリシーは、あるオリジンから読み込まれたスクリプトが別のオリジンのレスポンスを読み取ることを制限するブラウザのセキュリティ機構です。この制限がなければ、悪意のあるサイトがユーザーのブラウザ経由でログイン中の銀行サイトの API を呼び出し、その応答に含まれる残高や取引履歴を自分のスクリプトで読み取れてしまいます。

ここで押さえておきたいのは、既定で守っているのは同一オリジンポリシーの側であり、CORS はその制限を選択的に緩めるための仕組みだという関係です。「CORS を設定してクロスオリジンの攻撃を防ぐ」という理解は向きが逆で、実際には既定で閉じているものを必要な範囲だけ開ける操作にあたります。もう 1 点、同一オリジンポリシーが止めているのは応答の読み取りであって、リクエストの送信ではありません。送信自体は成立してしまうことが、CSRF が現実の脅威として残っている理由です。

しかし、現代の Web アプリケーションでは、フロントエンドとバックエンド API が異なるドメインで運用されるケースが一般的です。CORS は、サーバーが「どのオリジンからのアクセスを許可するか」を HTTP レスポンスヘッダーで明示することで、必要なクロスオリジン通信を安全に実現します。

CORS の動作メカニズム

CORS は、リクエストの種類に応じて 2 つの方式で動作します。

単純リクエスト (Simple Request)

メソッドが GET、HEAD、POST のいずれかで、付加するヘッダーが Accept、Accept-Language、Content-Language、Content-Type といったセーフリストの範囲に収まり、かつ Content-Type の値が application/x-www-form-urlencoded、multipart/form-data、text/plain のいずれかである場合、そのリクエストは「単純リクエスト」として扱われます。逆に言えば、Authorization や X-Requested-With のような独自のヘッダーを 1 つ足すだけで、この条件から外れます。

単純リクエストでは、ブラウザはリクエストをそのまま送信し、レスポンスの Access-Control-Allow-Origin ヘッダーを確認します。許可されたオリジンであればレスポンスを JavaScript に渡し、そうでなければ読み取りをブロックします。遮断されるのは JavaScript からの読み取りだけで、リクエストはサーバーに届き、処理も実行されています。ブラウザのコンソールに CORS エラーが出ていてもサーバー側ではデータが登録・更新されている場合があり、この違いは開発中の切り分けで必ず意識してください。

プリフライトリクエスト (Preflight Request)

PUT、DELETE、カスタムヘッダーを含むリクエストなど、単純リクエストの条件を満たさない場合、ブラウザは本来のリクエストの前に OPTIONS メソッドで「プリフライトリクエスト」を送信します。サーバーは以下のヘッダーで許可条件を応答します。

  • Access-Control-Allow-Origin: 許可するオリジン
  • Access-Control-Allow-Methods: 許可する HTTP メソッド
  • Access-Control-Allow-Headers: 許可するリクエストヘッダー
  • Access-Control-Max-Age: プリフライト結果のキャッシュ時間 (秒)

プリフライトの応答が許可条件を満たしていれば、ブラウザは本来のリクエストを送信します。

認証情報を含むリクエスト

Cookie や認証ヘッダーを含むクロスオリジンリクエストでは、Access-Control-Allow-Credentials: true が必要です。この場合、Access-Control-Allow-Origin にワイルドカード (*) は使用できず、具体的なオリジンを指定する必要があります。ワイルドカードが有効なのは認証情報を含まないリクエストに限る、という仕様上の排他であり、両方を同時に成立させる書き方は存在しません。Access-Control-Allow-Methods と Access-Control-Allow-Headers の * も同じで、認証情報付きのリクエストではワイルドカードとして扱われません。

もう 1 つの落とし穴は、プリフライトそのものには Cookie が付かないことです (仕様上、プリフライトの資格情報モードは常に same-origin と定められています)。OPTIONS リクエストにも認証を要求するサーバー設定やリバースプロキシ設定を入れると、本来のリクエストに到達する前に失敗し、原因の分かりにくい CORS エラーになります。

よくある設定ミスとセキュリティリスク

CORS の設定ミスは、同一オリジンポリシーによる保護を無効化し、深刻なセキュリティリスクを生みます。

  • Access-Control-Allow-Origin: * の安易な使用: すべてのオリジンを許可すると、任意のサイトから API にアクセス可能になる。公開 API 以外では使用すべきでない。特に認証情報を扱う API では絶対に使用してはならない
  • Origin ヘッダーの無検証な反映: リクエストの Origin ヘッダーの値をそのまま Access-Control-Allow-Origin に反映する実装は、実質的にワイルドカードと同じ。ホワイトリストで検証すべき
  • null オリジンの許可: Access-Control-Allow-Origin: null を許可すると、サンドボックス化された iframe やローカルファイルからのアクセスが可能になり、攻撃に悪用される
  • サブドメインの過剰な許可と後方一致の照合: *.example.com のようなパターンマッチで許可する場合、攻撃者がサブドメインを乗っ取れば CORS を悪用できる。さらに、末尾が一致するかだけを見る実装は、攻撃者が自分で取得した evil-example.com のような別ドメインまで通してしまう

CORS の設定ミスは XSS や CSRF と組み合わされることで、被害が拡大する可能性があります。一方で、CORS を厳しく設定しても CSRF は防げません。フォーム送信のような単純リクエストはプリフライトを発生させずにサーバーへ届くため、CSRF にはトークンや Cookie の SameSite 属性で別途対策する必要があります。

安全な CORS 設定のベストプラクティス

CORS を安全に設定するための指針を示します。

  • 許可するオリジンをホワイトリストで管理する: 環境変数や設定ファイルで許可オリジンのリストを管理し、リクエストの Origin ヘッダーと完全一致で検証する
  • 必要最小限のメソッドとヘッダーを許可する: Access-Control-Allow-Methods と Access-Control-Allow-Headers には、実際に使用するものだけを列挙する
  • プリフライトのキャッシュを活用する: Access-Control-Max-Age を明示してプリフライトリクエストの頻度を減らす。未指定時の既定値は仕様上 5 秒しかなく、実質すべてのリクエストの前に OPTIONS が飛ぶ。ただしブラウザ側にキャッシュ時間の上限があり、それを超える値は上限まで切り詰められるため、極端に長い秒数を書いても効果は伸びない
  • 認証情報を含むリクエストは慎重に扱う: Access-Control-Allow-Credentials: true を設定する場合、許可オリジンを厳密に制限する
  • CSP やセキュリティヘッダーと併用する: CORS 単独ではなく、他のセキュリティヘッダーと組み合わせて多層防御を構築する
  • HTTPS を前提とする: HTTP オリジンを許可リストに含めない。中間者攻撃によるオリジンの偽装を防ぐ

CORS はブラウザ側の制御であり、サーバー間通信や curl のようなコマンドラインツールからのリクエストには適用されません。攻撃者が自分の環境から API を直接呼び出す経路には効果がないため、CORS だけに依存せず、サーバー側の認証・認可を必ず実装してください。

なお CORS は、W3C 勧告「Cross-Origin Resource Sharing」(2014 年 1 月 16 日) として標準化された後、WHATWG の Fetch 標準に統合されました。細かい挙動を確認するときは Fetch 標準を参照するのが正確です。

よくある誤解

CORS はサーバーを保護するセキュリティ機能
CORS はブラウザ側の制御であり、サーバーを直接保護するものではない。curl やサーバー間通信では CORS の制限は適用されない。そもそも他オリジンのレスポンスの読み取りを禁じているのは同一オリジンポリシーで、CORS はその制限を緩める側の仕組み。ブラウザのユーザーを守る層であり、サーバー側の認証・認可とは別のレイヤーの対策。
CORS エラーが出たらワイルドカード (*) で解決すればよい
ワイルドカードはすべてのオリジンからのアクセスを許可するため、セキュリティリスクが高い。認証情報を含むリクエストでは使用できない。正しい対処は、必要なオリジンだけをホワイトリストに追加すること。
共有する

関連用語

関連記事