クロスオリジン リソース シェアリング(CORS)

クロスオリジン リソースを安全に共有する

Mariko Kosaka

ブラウザの同一オリジン ポリシーは、異なるオリジンからのリソースの読み取りをブロックします。このメカニズムにより、悪意のあるサイトが他のサイトのデータを読み取ることができなくなりますが、正当な使用も阻止されます。

最新のウェブアプリでは、別のドメインから JSON データを取得する場合や、別のサイトから <canvas> 要素に画像を読み込む場合など、異なるオリジンからリソースを取得することがよくあります。これらは誰でも読み取り可能な公開リソースにできますが、同一オリジン ポリシーにより使用がブロックされます。デベロッパーはこれまで、JSONP などの回避策を使用してきました。

クロスオリジン リソース シェアリング(CORS)は、この問題を標準化された方法で修正します。CORS を有効にすると、サーバーは追加のオリジンを使用できることをブラウザに通知できます。

ウェブでのリソース リクエストの仕組み

リクエストとレスポンス
クライアント リクエストとサーバー レスポンスの図。

ブラウザとサーバーは、ハイパーテキスト転送プロトコル(HTTP)を使用してネットワーク経由でデータを交換できます。HTTP は、リソースの取得に必要な情報など、リクエスト元とレスポンダー間の通信ルールを定義します。

HTTP ヘッダーは、クライアントとサーバー間のメッセージ交換をネゴシエートし、アクセスを決定するために使用されます。ブラウザのリクエストとサーバーのレスポンス メッセージはどちらもヘッダーと本文に分けられます。

メッセージの種類やメッセージのエンコードなど、メッセージに関する情報。ヘッダーには、Key-Value ペアとして表現されるさまざまな情報を含めることができます。リクエスト ヘッダーとレスポンス ヘッダーには異なる情報が含まれています。

リクエスト ヘッダーの例

Accept: text/html
Cookie: Version=1

このヘッダーは、「I want to receive HTML in response. 「これが私のクッキーです」

レスポンス ヘッダーの例

Content-Encoding: gzip
Cache-Control: no-store

このヘッダーは、「このレスポンスのデータは gzip でエンコードされています。キャッシュに保存しないでください。」

Body

メッセージ自体。書式なしテキスト、画像バイナリ、JSON、HTML など、さまざまな形式を使用できます。

CORS の仕組み

同一オリジン ポリシーは、クロスオリジン リクエストをブロックするようブラウザに指示します。別のオリジンの公開リソースが必要な場合、リソース提供サーバーは、リクエストを送信したオリジンがリソースにアクセスできることをブラウザに伝えます。ブラウザはこれを記憶し、そのリソースのクロスオリジン リソース シェアリングを許可します。

ステップ 1: クライアント(ブラウザ)リクエスト

ブラウザがクロスオリジン リクエストを行うと、ブラウザは Origin ヘッダーを現在のオリジン(スキーム、ホスト、ポート)とともに追加します。

ステップ 2: サーバー レスポンス

サーバーがこのヘッダーを確認し、アクセスを許可すると、リクエスト元のオリジンを指定する Access-Control-Allow-Origin ヘッダーをレスポンスに追加します(または、任意のオリジンを許可する場合は *)。

ステップ 3: ブラウザがレスポンスを受信する

ブラウザは、適切な Access-Control-Allow-Origin ヘッダーを含むこのレスポンスを確認すると、レスポンス データをクライアント サイトと共有します。

CORS と認証情報を共有する

プライバシー上の理由から、CORS は通常、リクエスト元が特定されない匿名リクエストに使用されます。CORS を使用して送信者を識別できる Cookie を送信する場合は、リクエストとレスポンスにヘッダーを追加する必要があります。

リクエスト

次の例に示すように、取得オプションに credentials: 'include' を追加します。これには、次のようにリクエストに Cookie が含まれます。

fetch('https://example.com', {
  mode: 'cors',
  credentials: 'include'
})

レスポンス

Access-Control-Allow-Origin を特定のオリジンに設定し(* を使用したワイルドカードなし)、Access-Control-Allow-Credentialstrue に設定する必要があります。

HTTP/1.1 200 OK
Access-Control-Allow-Origin: https://example.com
Access-Control-Allow-Credentials: true

複雑な HTTP 呼び出しのプリフライト リクエスト

ウェブアプリが複雑な HTTP リクエストを行うと、ブラウザはプリフライト リクエストをリクエスト チェーンの先頭に追加します。

CORS 仕様では、複雑なリクエストを次のように定義します。

  • GET、POST、HEAD 以外のメソッドを使用するリクエスト。
  • AcceptAccept-LanguageContent-Language 以外のヘッダーを含むリクエスト。
  • リクエストに application/x-www-form-urlencodedmultipart/form-datatext/plain 以外の Content-Type ヘッダーがある。

ブラウザは必要なプリフライト リクエストを自動的に作成し、実際のリクエスト メッセージの前に送信します。プリフライト リクエストは、次の例のような OPTIONS リクエストです。

OPTIONS /data HTTP/1.1
Origin: https://example.com
Access-Control-Request-Method: DELETE

サーバー側では、リクエストを受信したアプリが、このオリジンからアプリケーションが受け入れるメソッドに関する情報を使用してプリフライト リクエストに応答します。

HTTP/1.1 200 OK
Access-Control-Allow-Origin: https://example.com
Access-Control-Allow-Methods: GET, DELETE, HEAD, OPTIONS

サーバー レスポンスには、プリフライトの結果をキャッシュに保存する期間を秒単位で指定する Access-Control-Max-Age ヘッダーを含めることもできます。これにより、クライアントはプリフライト リクエストを繰り返すことなく、複数の複雑なリクエストを送信できます。