クロスオリジン リソースを安全に共有する
ブラウザの同一生成元ポリシーにより、異なる生成元からのリソースの読み取りがブロックされます。このメカニズムにより、悪意のあるサイトが他のサイトのデータを読み取るのを防ぐことができますが、正当な使用も妨げられます。
最近のウェブアプリでは、異なるオリジンからリソースを取得することがよくあります。たとえば、異なるドメインから JSON データを取得したり、別のサイトから <canvas> 要素に画像を読み込んだりします。これらは、誰でも読み取れるように公開されているリソースですが、同一オリジン ポリシーによって使用がブロックされています。これまで、デベロッパーは JSONP などの回避策を使用してきました。
クロスオリジン リソース シェアリング(CORS)は、この問題を標準化された方法で解決します。CORS を有効にすると、サーバーはブラウザに追加のオリジンを使用できることを通知します。
ウェブでのリソース リクエストの仕組み
ブラウザとサーバーは、Hypertext Transfer Protocol(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-Credentials は true に設定する必要があります。
HTTP/1.1 200 OK
Access-Control-Allow-Origin: https://example.com
Access-Control-Allow-Credentials: true
複雑な HTTP 呼び出しのプリフライト リクエスト
ウェブアプリが複雑な HTTP リクエストを行うと、ブラウザはリクエスト チェーンの先頭にプリフライト リクエストを追加します。
CORS 仕様では、複雑なリクエストを次のように定義しています。
- GET、POST、HEAD 以外のメソッドを使用するリクエスト。
Accept、Accept-Language、Content-Language以外のヘッダーを含むリクエスト。application/x-www-form-urlencoded、multipart/form-data、text/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 ヘッダーを含めることもできます。これにより、クライアントはプリフライト リクエストを繰り返すことなく、複数の複雑なリクエストを送信できます。