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

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

Mariko Kosaka

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

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

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

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

リクエストとレスポンス
クライアント リクエストとサーバー レスポンスを示しています。

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

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

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

リクエスト ヘッダーの例

Accept: text/html
Cookie: Version=1

このヘッダーは、「レスポンスで HTML を受信したい。ここにクッキーがあります。」

レスポンス ヘッダーの例

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

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

本文

メッセージ自体。プレーン テキスト、画像バイナリ、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 ヘッダーを含めることもできます。これにより、クライアントはプリフライト リクエストを繰り返すことなく、複数の複雑なリクエストを送信できます。