クロスサイトリクエストフォージェリ(CSRF)などのセキュリティ攻撃を防止するために、ブラウザは「同一生成元ポリシー(Same-Origin Policy)」という仕組みを実装し、異なるオリジンのリソースへのアクセスに制約をかけています。CORS (Cross-Origin Resource Sharing)は、この制約を一部解除し、異なるオリジン間でリソースを共有するための仕組みです。
例えば、Site-A(site-a.example.com) から他オリジンの Site-B(site-b.example.com) のリソースやAPIを参照したい場合、Site-A を閲覧中のブラウザは Site-B へのリクエストヘッダにアクセス元のオリジン情報を付加します。XMLHttpRequest によるアクセスや、crossorigin="anonymous" を指定した img, script, audio, video, link アクセスの場合などに、Origin: ヘッダが付与されます。
Origin: http://site-a.example.com
これに対し、site-b 側で、site-a へのアクセスを許可する場合、下記の様なレスポンスヘッダを返します。
Access-Control-Allow-Origin: http://site-a.example.com
すべてのオリジンに対してアクセスを許可する場合、ワイルドカード(*) を使用することができます。
Access-Control-Allow-Origin: *
上記のやりとりは「単純リクエスト」と呼ばれるもので、下記の条件が満たされる場合に利用可能なシーケンスです。
上記の条件を満たせない場合は、「プリフライトリクエスト」と呼ばれるもう少し複雑なシーケンスとなります。下記は、条件に含まれてないヘッダ (X-Custom-Header) を送信する例です。まず、Site-A を閲覧中のブラウザ は Site-B に対して、リクエストしたい情報を OPTIONS で事前確認します。
OPTIONS /some-url HTTP/1.1 Origin: http://site-a.example.com Access-Control-Request-Method: POST Access-Control-Request-Headers: X-Custom-Header, Content-Type
これに対し、Site-B は、アクセスを許可する・しないの情報を返します。
Access-Control-Allow-Origin: http://site-a.example.com Access-Control-Allow-Methods: POST, GET, OPTIONS Access-Control-Allow-Headers: X-Custom-Header, Content-Type Access-Control-Max-Age: 86400
アクセスの許可が得られたのちに、ブラウザは実際のリクエストを送信します。
POST /some-url HTTP/1.1 Content-Type: text/json X-Custom-Header: custom-data
Site-B がこれに応答します。
HTTP/1.1 200 OK
Access-Control-Max-Age で指定した時間が過ぎるまでは、OPTIONS による事前確認なしに POST することができます。
Site-A から Site-B に Site-A の Cookie や HTTP認証による認証情報を渡す場合は、Site-A のスクリプト側で withCredentials フラグを true にし、Site-B からの OPTIONS 応答で Access-Control-Allow-Credentials: true が返却される必要があります。
<script> window.addEventListener('load', function() { var xhr = new XMLHttpRequest(); xhr.onreadystatechange = function() { if (xhr.readyState == 4) { console.log("status = " + xhr.status); console.log(xhr.responseText); } } xhr.open("POST", "http://site-b.example.com/"); xhr.withCredentials = true; xhr.setRequestHeader("Content-Type" , "text/json"); xhr.send(JSON.stringify({"sid": getCookie("sid")})); }); </script>
Site-A を閲覧中のブラウザは通常通りの事前確認用の OPTIONS を送信します。
OPTIONS /test HTTP/1.1 Origin: http://site-a.example.com Access-Control-Request-Method: POST Access-Control-Request-Headers: X-Custom-Header, Content-Type
Site-B は、Access-Control-Allow-Credentials: true を返却します。
Access-Control-Allow-Origin: http://site-a.example.com Access-Control-Allow-Methods: POST, GET, OPTIONS Access-Control-Allow-Headers: X-Custom-Header, Content-Type Access-Control-Max-Age: 86400 Access-Control-Allow-Credentials: true
これにより、Site-A の JavaScript は、Cookie などの認証情報を Site-B に POST することが許可されます。