--- title: オリジン間リソース共有 (CORS) slug: Web/HTTP/CORS tags: - AJAX - CORS - Fetch - Fetch API - HTTP - HTTP アクセス制御 - Security - XMLHttpRequest - 'l10n:priority' - オリジン間リソース共有 - セキュリティ - 同一オリジンポリシー translation_of: Web/HTTP/CORS ---
オリジン間リソース共有 ({{Glossary("CORS")}}) は、追加の {{Glossary("HTTP")}} ヘッダーを使用して、ある{{glossary("origin", "オリジン")}}で動作しているウェブアプリケーションに、異なるオリジンにある選択されたリソースへのアクセス権を与えるようブラウザーに指示するための仕組みです。ウェブアプリケーションは、自分とは異なるオリジン (ドメイン、プロトコル、ポート番号) にあるリソースをリクエストするとき、オリジン間 HTTP リクエストを実行します。
オリジン間リクエストの一例: https://domain-a.com
で提供されているウェブアプリケーションのフロントエンド JavaScript コードが {{domxref("XMLHttpRequest")}} を使用して https://domain-b.com/data.json
へリクエストを行う場合。
セキュリティ上の理由から、ブラウザーは、スクリプトによって開始されるオリジン間 HTTP リクエストを制限しています。例えば、 XMLHttpRequest
や Fetch API は同一オリジンポリシーに従います。つまり、これらの API を使用するウェブアプリケーションは、そのアプリケーションが読み込まれたのと同じオリジンに対してのみリソースのリクエストを行うことができ、それ以外のオリジンの場合は正しい CORS ヘッダーを含んでいることが必要です。
CORS の仕組みは、安全なオリジン間のリクエストとブラウザー・サーバー間のデータ転送を支援します。最近のブラウザーは CORS を XMLHttpRequest
や Fetch などの API で使用して、オリジン間 HTTP リクエストのリスクの緩和に役立てています。
誰もが読むべきです。
もっと具体的に言えば、この記事はウェブ管理者、サーバー開発者、フロントエンド開発者向けです。最近のブラウザーはヘッダーやポリシーの強制を含む、オリジン間共有のクライアント側コンポーネントを扱います。しかし CORS 標準は、サーバーが新たなリクエストヘッダーやレスポンスヘッダーを扱わなければならないことを示しています。サーバー開発者向けには、サーバーの観点によるオリジン間共有 (PHP コードスニペット付き) についての議論を合わせてお読みください。
このオリジン間共有仕様は、以下のようなサイト間 HTTP リクエストを有効にすることができます。
@font-face
で別ドメインのフォントを利用するため)。これによりサーバーは、許可したウェブサイトのみから読み込みや利用ができる TrueType フォントを提供できます。この記事では、オリジン間リソース共有の全般的な説明と併せて、 HTTP ヘッダーの要件についても説明します。
オリジン間リソース共有の仕様は、ウェブブラウザーから情報を読み取ることを許可されているオリジンをサーバーが記述することができる、新たな HTTP ヘッダーを追加することで作用します。加えて仕様書では、サーバーの情報に副作用を引き起こすことがある HTTP のリクエストメソッド (特に {{HTTPMethod("GET")}} 以外の HTTP メソッドや、特定の MIME タイプを伴う {{HTTPMethod("POST")}}) のために、ブラウザーが HTTP の {{HTTPMethod("OPTIONS")}} リクエストメソッドを用いて、あらかじめリクエストの「プリフライト」 (サーバーから対応するメソッドの一覧を収集すること) を行い、サーバーの「認可」のもとに実際のリクエストを送信することを指示しています。サーバーはリクエスト時に「資格情報」 (Cookie や HTTP 認証 など) を送信するべきかをクライアントに伝えることもできます。
CORS は様々なエラーで失敗することがありますが、セキュリティ上の理由から、エラーについて JavaScript から知ることができないよう定められています。コードからはエラーが発生したということしか分かりません。何が悪かったのかを具体的に知ることができる唯一の方法は、ブラウザーのコンソールで詳細を見ることです。
以降の節ではシナリオの説明に加え、 HTTP ヘッダーの使い方の詳細も提供します。
オリジン間リソース共有がどのように動作するかを説明する3つのシナリオを示します。これらの例はすべて {{domxref("XMLHttpRequest")}} を用いており、対応しているブラウザーにおいて、サイトをまたいでアクセスすることができます。
サーバー側から見たオリジン間リソース共有の説明 (PHP のコードスニペットを含む) は Server-Side Access Control (CORS) の記事にあります。
リクエストによっては CORS プリフライトを引き起こさないものがあります。これをこの記事では「単純リクエスト」と呼んでいますが、 (CORS を定義している) {{SpecName('Fetch')}} 仕様書ではこの用語を使用していません。 「単純リクエスト」は、以下のすべての条件を満たすものです。
DPR
Save-Data
Viewport-Width
Width
application/x-www-form-urlencoded
multipart/form-data
text/plain
注: WebKit Nightly および Safari Technology Preview は、 {{HTTPHeader("Accept")}}, {{HTTPHeader("Accept-Language")}}, {{HTTPHeader("Content-Language")}} ヘッダーの値に追加の制限を掛けています。これらのヘッダーが「標準外」の値の場合、 WebKit/Safari はそのリクエストが「単純リクエスト」の条件に合うとは判断しません。 WebKit/Safari がこれらのヘッダーのどの値を「標準外」と判断するかについては、以下の WebKit のバグを除いて文書化されていません。
これは仕様の一部ではないので、他のブラウザーはこの追加の制限を実装していません。
例えば、ドメイン https://foo.example
にあるウェブコンテンツがドメイン https://bar.other
にあるコンテンツを呼び出したいと仮定します。以下のようなコードが foo.example
内の JavaScript で使用されるかもしれません。
const xhr = new XMLHttpRequest(); const url = 'https://bar.other/resources/public-data/'; xhr.open('GET', url); xhr.onreadystatechange = someHandler; xhr.send();
これは、特権を扱うために CORS ヘッダーを使用して、クライアントとサーバーの間で簡単なデータ交換を行います。
この場合、ブラウザーがサーバーに何を送信し、サーバーが何を返すかを見てみましょう。
GET /resources/public-data/ HTTP/1.1 Host: bar.other User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.14; rv:71.0) Gecko/20100101 Firefox/71.0 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 Accept-Language: en-us,en;q=0.5 Accept-Encoding: gzip,deflate Connection: keep-alive Origin: https://foo.example
特筆すべきリクエストヘッダーは {{HTTPHeader("Origin")}} であり、呼び出しが https://foo.example
から来たことを表します。
HTTP/1.1 200 OK Date: Mon, 01 Dec 2008 00:23:53 GMT Server: Apache/2 Access-Control-Allow-Origin: * Keep-Alive: timeout=2, max=100 Connection: Keep-Alive Transfer-Encoding: chunked Content-Type: application/xml […XML データ…]
レスポンスでは、サーバーが {{HTTPHeader("Access-Control-Allow-Origin")}} ヘッダーを返信しています。 {{HTTPHeader("Origin")}} ヘッダーと {{HTTPHeader("Access-Control-Allow-Origin")}} ヘッダーの使用は、最も単純なアクセス制御プロトコルを表しています。この場合、サーバーは Access-Control-Allow-Origin: *
を返しており、これはそのリソースがすべてのドメインからアクセスできることを意味します。 https://bar.other
にあるリソースの所有者が、リソースへの制限を https://foo.example
からのリクエストのみに制限したいと考えていた場合は、以下のように送信します。
Access-Control-Allow-Origin: https://foo.example
https://foo.example
以外のドメインはすべて、サイト間の方法でリソースにアクセスすることがサイト間の方法でリソースにアクセスすることができなくなりました。リソースへのアクセスを許可するには、 Access-Control-Allow-Origin
ヘッダーに、リクエストの Origin
ヘッダーの中で送信された値を含めてください。
「単純リクエスト」 (前述) とは異なり、「プリフライト」リクエストは始めに {{HTTPMethod("OPTIONS")}} メソッドによる HTTP リクエストを他のドメインにあるリソースに向けて送り、実際のリクエストを送信しても安全かどうかを確かめます。サイト間リクエストがユーザーデータに影響を与える可能性があるような場合に、このようにプリフライトを行います。
以下は、プリフライトが行われるリクエストの例です。
const xhr = new XMLHttpRequest(); xhr.open('POST', 'https://bar.other/resources/post-here/'); xhr.setRequestHeader('X-PINGOTHER', 'pingpong'); xhr.setRequestHeader('Content-Type', 'application/xml'); xhr.onreadystatechange = handler; xhr.send('<person><name>Arun</name></person>');
上記の例では、 POST
で送信する XML の本体を作成しています。また、標準外の X-PINGOTHER
HTTP リクエストヘッダーを設定しています。このようなヘッダーは HTTP/1.1 プロトコルに含まれていませんが、ウェブアプリケーションでは一般的に便利なものです。リクエストで Content-Type
に application/xml
を使用しており、かつカスタムヘッダーを設定しているため、このリクエストではプリフライトを行います。
注: 後述するように、実際の POST
リクエストには Access-Control-Request-*
ヘッダーが含まれず、 OPTIONS
リクエストのみで必要になります。
クライアントとサーバーとの間のやりとりの全容を見てみましょう。最初のやり取りはプリフライトリクエスト/レスポンスです。
OPTIONS /doc HTTP/1.1 Host: bar.other User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.14; rv:71.0) Gecko/20100101 Firefox/71.0 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 Accept-Language: en-us,en;q=0.5 Accept-Encoding: gzip,deflate Connection: keep-alive Origin: http://foo.example Access-Control-Request-Method: POST Access-Control-Request-Headers: X-PINGOTHER, Content-Type HTTP/1.1 204 No Content Date: Mon, 01 Dec 2008 01:15:39 GMT Server: Apache/2 Access-Control-Allow-Origin: https://foo.example Access-Control-Allow-Methods: POST, GET, OPTIONS Access-Control-Allow-Headers: X-PINGOTHER, Content-Type Access-Control-Max-Age: 86400 Vary: Accept-Encoding, Origin Keep-Alive: timeout=2, max=100 Connection: Keep-Alive
プリフライトリクエストが完了したら、実際のリクエストを送ります。
POST /doc HTTP/1.1 Host: bar.other User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.14; rv:71.0) Gecko/20100101 Firefox/71.0 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 Accept-Language: en-us,en;q=0.5 Accept-Encoding: gzip,deflate Connection: keep-alive X-PINGOTHER: pingpong Content-Type: text/xml; charset=UTF-8 Referer: https://foo.example/examples/preflightInvocation.html Content-Length: 55 Origin: https://foo.example Pragma: no-cache Cache-Control: no-cache <person><name>Arun</name></person> HTTP/1.1 200 OK Date: Mon, 01 Dec 2008 01:15:40 GMT Server: Apache/2 Access-Control-Allow-Origin: https://foo.example Vary: Accept-Encoding, Origin Content-Encoding: gzip Content-Length: 235 Keep-Alive: timeout=2, max=99 Connection: Keep-Alive Content-Type: text/plain [Some XML payload]
上記の1-10行目は {{HTTPMethod("OPTIONS")}} メソッドによるプリフライトを表します。ブラウザーは上記で使用された JavaScript コードで使用しているリクエストの引数に基づいて、プリフライトの送信が必要であることを判断します。これによりサーバーは実際のリクエストの引数によって送られるリクエストを受け入れ可能かをレスポンスできます。 OPTIONS はサーバーから付加的な情報を得るために用いる HTTP/1.1 のメソッドであり、また{{Glossary("safe","安全")}}なメソッド、つまりリソースを変更するためには使用できないメソッドです。 OPTIONS リクエストと合わせて、他にリクエストヘッダーを2つ送信していることに注意してください (それぞれ9行目と10行目です)。
Access-Control-Request-Method: POST Access-Control-Request-Headers: X-PINGOTHER, Content-Type
{{HTTPHeader("Access-Control-Request-Method")}} ヘッダーは、プリフライトリクエストの一部として、実際のリクエストが POST
リクエストメソッドで送られることをサーバーに通知します。 {{HTTPHeader("Access-Control-Request-Headers")}} ヘッダーは、実際のリクエストにカスタムヘッダーである X-PINGOTHER
および Content-Type が含まれることをサーバーに通知します。ここでサーバーは、この状況下でリクエストの受け入れを望むかを判断する機会があります。
上記の13-22行目はサーバーが返すレスポンスであり、リクエストメソッド (POST
) とリクエストヘッダー (X-PINGOTHER
) を受け入れられることを示しています。特に、16-19行目を見てみましょう。
Access-Control-Allow-Origin: http://foo.example Access-Control-Allow-Methods: POST, GET, OPTIONS Access-Control-Allow-Headers: X-PINGOTHER, Content-Type Access-Control-Max-Age: 86400
サーバーは Access-Control-Allow-Methods
を返しており、これは当該リソースへの問い合わせで POST
および GET
が実行可能なメソッドであることを伝えます。なお、このヘッダーはレスポンスヘッダーの {{HTTPHeader("Allow")}} と似ていますが、アクセス制御でのみ使用されることに注意してください。
またサーバーは、 Access-Control-Allow-Headers
を X-PINGOTHER
の値で送信し、これが実際のリクエストで使用されるヘッダーであることを承認しています。 Access-Control-Allow-Methods
と同様に、 Access-Control-Allow-Headers
は受け入れ可能なヘッダーをカンマ区切りのリストで表します。
最後に Access-Control-Max-Age
は、プリフライトリクエストを再び送らなくてもいいように、プリフライトのレスポンスをキャッシュしてよい時間を秒数で与えます。この例では86400秒、つまり24時間です。なお、ブラウザーは個々に内部の上限値を持っており、 Access-Control-Max-Age
が上回った場合に制限を掛けます。
多くのブラウザーは現在、下記のようなプリフライトリクエストのリダイレクトに対応していません。プリフライトリクエストにリダイレクトが発生すると、多くのブラウザーは以下のようなエラーメッセージを報告します。
リクエストがプリフライトを必要とするオリジン間リクエストで許可されていない 'https://example.com/foo' にリダイレクトされました。
リクエストにはプリフライトが必要で、オリジン間のリダイレクトは許可されていません
もともと CORS プロトコルはそのような振る舞いを要求していましたが、その後で必要がないと変更されました。しかし、多くのブラウザーはまだ変更を実装しておらず、もともと要求されていた振る舞いに従っています。
ブラウザーが仕様に追いつくまで、以下の一方もしくは両方を行うことでこの制限を回避することができます。
これらの変更ができない場合は、次のような別な方法があります。
Response.url
または XMLHttpRequest.responseURL
で得た URL を使用して、もう一つのリクエスト (「本当の」リクエスト) を行う。ただし、リクエストに Authorization
ヘッダーが存在するためにプリフライトを引き起こすリクエストの場合、上記の手順を使用して制限を回避することはできません。リクエストが行われているサーバーを制御できない限り、まったく回避することはできません。
{{domxref("XMLHttpRequest")}} や Fetch と CORS の両方によって明らかになる最も興味深い機能は、 HTTP クッキーと HTTP 資格情報によってわかる「資格情報を含む」リクエストを作成することができることです。既定では、サイト間の XMLHttpRequest
または Fetch の呼び出しにおいて、ブラウザーは資格情報を送信しません。 XMLHttpRequest
オブジェクトまたは {{domxref("Request")}} のコンストラクターの呼び出し時に、特定のフラグを設定する必要があります。
以下の例では http://foo.example
から読み込まれた元のコンテンツが、 http://bar.other
にあるリソースに対してクッキーを設定したシンプルな GET リクエストを行います。 foo.example のコンテンツは以下のような JavaScript を含んでいるかもしれません。
const invocation = new XMLHttpRequest(); const url = 'http://bar.other/resources/credentialed-content/'; function callOtherDomain() { if (invocation) { invocation.open('GET', url, true); invocation.withCredentials = true; invocation.onreadystatechange = handler; invocation.send(); } }
7行目で、クッキー付きで呼び出しを行うために {{domxref("XMLHttpRequest")}} に設定する必要があるフラグ、 withCredentials
という真偽値型の値を示しています。既定では、クッキーなしで呼び出しが行われます。これは単純な GET
リクエストなのでプリフライトは行いませんが、ブラウザーは {{HTTPHeader("Access-Control-Allow-Credentials")}}: true
ヘッダーを持たないレスポンスを拒否し、ウェブコンテンツを呼び出すレスポンスを作成しないでしょう。
以下はクライアントとサーバーとの間のやりとりの例です。
GET /resources/credentialed-content/ HTTP/1.1 Host: bar.other User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.14; rv:71.0) Gecko/20100101 Firefox/71.0 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 Accept-Language: en-us,en;q=0.5 Accept-Encoding: gzip,deflate Connection: keep-alive Referer: http://foo.example/examples/credential.html Origin: http://foo.example Cookie: pageAccess=2 HTTP/1.1 200 OK Date: Mon, 01 Dec 2008 01:34:52 GMT Server: Apache/2 Access-Control-Allow-Origin: https://foo.example Access-Control-Allow-Credentials: true Cache-Control: no-cache Pragma: no-cache Set-Cookie: pageAccess=3; expires=Wed, 31-Dec-2008 01:34:53 GMT Vary: Accept-Encoding, Origin Content-Encoding: gzip Content-Length: 106 Keep-Alive: timeout=2, max=100 Connection: Keep-Alive Content-Type: text/plain [text/plain payload]
10行目に http://bar.other
向けのクッキーが含まれていますが、bar.other が {{HTTPHeader("Access-Control-Allow-Credentials")}}: true
(17行目) をレスポンスに含めなければ、レスポンスは無視されウェブコンテンツで使用できません。
資格情報を含むリクエストに対するレスポンスの時、サーバーは Access-Control-Allow-Origin
ヘッダーで "*
" ワイルドカードではなくオリジンを指定しなければなりません。
上記の例のリクエストヘッダーは Cookie
ヘッダーを含んでいるため、 Access-Control-Allow-Origin
ヘッダーが "*" であったらリクエストは失敗します。 Access-Control-Allow-Origin
ヘッダーの値が "*
" ワイルドカードではなく "http://foo.example
" (実際のオリジン) なので、ウェブコンテンツの呼び出しに対して資格情報を意識したコンテンツが返ります。
なお、上記の例の中にある Set-Cookie
レスポンスヘッダーは、将来のクッキーの設定も行ないます。失敗した場合、 (使われている API によりますが) 例外が発生します。
CORS のレスポンスに設定されたクッキーは、サードパーティーのクッキーに関する通常のポリシーに従います。上記の例では、ページは foo.example
から読み込まれていますが、20行目のクッキーは bar.other
から送られているので、ユーザーがブラウザーでサードパーティーのクッキーをすべて拒否するよう設定していた場合は保存されません。
ここではオリジン間リソース共有の仕様書で定義されている、アクセス制御のためにサーバーが返す HTTP レスポンスヘッダーを掲載します。前の章では、これらの実際の動作の概要を説明しました。
返却されるリソースには、以下のような構文で1つの {{HTTPHeader("Access-Control-Allow-Origin")}} ヘッダーがつくことがあります。
Access-Control-Allow-Origin: <origin> | *
Access-Control-Allow-Origin
は、リソースへのアクセスを許可するオリジンをブラウザーに伝えるための単一のオリジン、または — 資格情報を含まないリクエストにおいては — どのオリジンにもリソースへのアクセスを許可することをブラウザーに伝えるワイルドカード "*
" のどちらかを指定することができます。
例えば、 https://mozilla.org
のオリジンからのコードにリソースへのアクセスを許可するには、次のように指定します。
Access-Control-Allow-Origin: https://mozilla.org Vary: Origin
サーバーがワイルドカード "*
" ではなく (ホワイトリストの一部としてリクエストするオリジンに基づいて動的に変更される可能性がある) 単一のオリジンを指定した場合は、サーバーは {{HTTPHeader("Vary")}} レスポンスヘッダーに Origin
も含めて、サーバーのレスポンスが {{HTTPHeader("Origin")}} リクエストヘッダーの値によって変化することをクライアントに示してください。
{{HTTPHeader("Access-Control-Expose-Headers")}} ヘッダーは、ブラウザーがアクセスを許可されるサーバーのホワイトリストにあるヘッダーを示すことができます。
Access-Control-Expose-Headers: <header-name>[, <header-name>]*
例えば、以下のようになります。
Access-Control-Expose-Headers: X-My-Custom-Header, X-Another-Custom-Header
これは、ブラウザーに対して X-My-Custom-Header
および X-Another-Custom-Header
ヘッダーを許可します。
このヘッダーはプリフライトリクエストの結果をキャッシュしてよい時間を示します。プリフライトリクエストの例は、前出の例をご覧ください。
Access-Control-Max-Age: <delta-seconds>
delta-seconds
引数は、結果をキャッシュしてよい時間を秒単位で示します。
{{HTTPHeader("Access-Control-Allow-Credentials")}} は credentials
フラグが真であるときに、リクエストへのレスポンスを開示してよいか否かを示します。プリフライトリクエストのレスポンスの一部として用いられたときは、実際のリクエストで資格情報を使用してよいか否かを示します。単純な GET
リクエストはプリフライトを行いませんので、リソースへのリクエストが資格情報付きで行われた場合にリソースと共にこのヘッダーを返さなければ、レスポンスはブラウザーによって無視され、ウェブコンテンツに返らないことに注意してください。
Access-Control-Allow-Credentials: true
資格情報付きのリクエストは前に説明したとおりです。
{{HTTPHeader("Access-Control-Allow-Methods")}} ヘッダーは、リソースへのアクセス時に許可するメソッドを指定します。これはプリフライトリクエストのレスポンスで用いられます。リクエストのプリフライトを行う条件については前述のとおりです。
Access-Control-Allow-Methods: <method>[, <method>]*
ブラウザーにこのヘッダーを送信する例を含む、プリフライトリクエストの例は 前述のとおりです。
{{HTTPHeader("Access-Control-Allow-Headers")}} ヘッダーは、実際のリクエストでどの HTTP ヘッダーを使用できるかを示すために、プリフライトリクエストのレスポンスで使用します。
Access-Control-Allow-Headers: <header-name>[, <header-name>]*
この節では、 HTTP リクエストを発行する際、オリジン間リソース共有機能を利用するためにクライアントが使用できるヘッダーの一覧を掲載します。なお、これらのヘッダーはサーバーの呼び出し時に設定されます。サイト間 {{domxref("XMLHttpRequest")}} の機能を使用する開発者は、オリジン間リソース共有のヘッダーをプログラムで設定する必要はありません。
{{HTTPHeader("Origin")}} ヘッダーはサイト間のアクセスリクエストやプリフライトリクエストのオリジンを示します。
Origin: <origin>
origin は、リクエストを開始したサーバーを示す URI です。ここにパス情報は含めず、サーバー名だけにします。
origin
の値は null
または URI にすることができます。すべてのアクセス制御リクエストにおいて、 {{HTTPHeader("Origin")}} ヘッダーは常に送信されることに注意してください。
{{HTTPHeader("Access-Control-Request-Method")}} はプリフライトリクエストを発信する際に、実際のリクエストを行う際に使用する HTTP メソッドをサーバーに知らせるために使用します。
Access-Control-Request-Method: <method>
使用例は前出のとおりです。
{{HTTPHeader("Access-Control-Request-Headers")}} ヘッダーは、プリフライトリクエストを発信する際に、実際のリクエストを行う際に使用する HTTP ヘッダーをサーバーに知らせるために使用します。
Access-Control-Request-Headers: <field-name>[, <field-name>]*
使用例は 前出のとおりです。
仕様書 | 状態 | 備考 |
---|---|---|
{{SpecName('Fetch', '#cors-protocol', 'CORS')}} | {{Spec2('Fetch')}} | W3C CORS 仕様書を置き換える新しい定義です。 |
{{Compat("http.headers.Access-Control-Allow-Origin")}}
Internet Explorer 8 および 9 は XDomainRequest オブジェクトで CORS を提供していますが、完全な実装は IE 10 で行っています。