公開日: 2018 年 11 月 5 日
ブラウザの同一オリジン ポリシーにより、異なるオリジンからリソースを読み取ることはできません。このメカニズムにより、悪意のあるサイトが他のサイトのデータを読み取るのを防ぐことができますが、正当な使用も妨げられます。
最近のウェブアプリでは、異なるオリジンからリソースを取得することがよくあります。たとえば、異なるドメインから JSON データを取得したり、別のサイトから
<canvas>要素に画像を読み込んだりします。これらは誰でも読み取れるように公開されているリソースですが、同一オリジン ポリシーにより使用できません。デベロッパーはこれまで、
JSONPなどの回避策を使用してきました。
クロスオリジン リソース シェアリング(CORS) は、この問題を標準化された方法で解決します。CORS を有効にすると、サーバーは追加のオリジンを使用できることをブラウザに通知できます。
ウェブでのリソース リクエストの仕組み
ブラウザとサーバーは、HTTP(Hypertext Transfer Protocol) を使用してネットワーク経由でデータを交換できます。HTTP は、リソースを取得するために必要な情報など、リクエスタとレスポンダ間の通信ルールを定義します。
HTTP ヘッダーは、クライアントとサーバー間のメッセージ交換をネゴシエートし、アクセス権の決定に使用されます。ブラウザのリクエストとサーバーのレスポンス メッセージは、ヘッダー と本文 に分割されます。
ヘッダー
メッセージの種類やメッセージのエンコードなど、メッセージに関する情報。ヘッダーには、 Key-Value ペアで表されるさまざまな情報 を含めることができます。リクエスト ヘッダーとレスポンス ヘッダーには異なる情報が含まれます。
リクエスト ヘッダーの例
Accept: text/html
Cookie: Version=1
このヘッダーは、「レスポンスで HTML を受け取りたい。ここに Cookie があります」と言うのと同じです。
レスポンス ヘッダーの例
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' を fetch オプションに追加します。
これにより、リクエストに 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以外のヘッダーを含むリクエスト。Content-Typeヘッダーがapplication/x-www-form-urlencoded、multipart/form-data、text/plain以外のリクエスト。
ブラウザは、必要なプリフライト リクエストを自動的に作成し、実際のリクエスト メッセージの前に送信します。プリフライト リクエストは、次の例のような 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 ヘッダーを含めることもできます。これにより、クライアントはプリフライト リクエストを繰り返すことなく、複数の複雑なリクエストを送信できます。