CORS(Cross-Origin Resource Sharing)

トップ > アラカルト > CORS(Cross-Origin Resource Sharing)

CORSとは

クロスサイトリクエストフォージェリ(CSRF)などのセキュリティ攻撃を防止するために、ブラウザは「同一生成元ポリシー(Same-Origin Policy)」という仕組みを実装し、異なるオリジンのリソースへのアクセスに制約をかけています。CORS (Cross-Origin Resource Sharing)は、この制約を一部解除し、異なるオリジン間でリソースを共有するための仕組みです。

CORS の仕組み

例えば、site-a.example.com から他オリジンの site-b.example.com のリソースを参照したい場合、ブラウザは site-b へのリクエストヘッダにアクセス元のオリジン情報を付加します。XMLHttpRequest によるアクセスや、crossorigin="anonymous" を指定した img, script, audio, video, link アクセスの場合などに、Origin: ヘッダが付与されます。

Site-A → Site-B
Origin: http://site-a.example.com

これに対し、site-b 側で、site-a へのアクセスを許可する場合、下記の様なレスポンスヘッダを返します。

Site-B → Site-A
Access-Control-Allow-Origin: http://site-a.example.com

すべてのオリジンに対してアクセスを許可する場合、ワイルドカード(*) を使用することができます。

Site-B → Site-A
Access-Control-Allow-Origin: *

単純リクエストとプリフライトリクエスト

上記のやりとりは「単純リクエスト」と呼ばれるもので、下記の条件が満たされる場合に利用可能なシーケンスです。

上記の条件を満たせない場合は、「プリフライトリクエスト」と呼ばれるもう少し複雑なシーケンスとなります。下記は、条件に含まれてないヘッダ (X-Custom-Header) を送信する例です。まず、Site-A は Site-B に対して、リクエストしたい情報を OPTIONS で事前確認します。

Site-A → Site-B
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 は、アクセスを許可する・しないの情報を返します。

Site-B → Site-A
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

アクセスの許可が得られたのちに、Site-A は実際のリクエストを送信します。

Site-A → Site-B
POST /test HTTP/1.1
Content-Type: text/json
X-Custom-Header: custom-data

Site-B がこれに応答します。Access-Control-Max-Age で指定した時間が過ぎるまでは、OPTIONS による事前確認なしに POST します。

Site-B → Site-A
HTTP/1.1 200 OK

資格情報を含むリクエスト

Site-A から Site-B に対して、Site-A の Cookie や HTTP認証による認証情報を渡す場合は、Site-A 側で withCredentials フラグを true にし、Site-B からの OPTIONS 応答で Access-Control-Allow-Credentials フラグで true が返却される必要があります。

Site-A
<script>
window.onload = 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 を送信します。

Site-A → Site-B
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 を返却します。

Site-B → Site-A
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 は、Cookie などの認証情報を Site-B に POST することが許可されます。


Copyright (C) 2018 杜甫々
初版:2018年12月30日 最終更新:2018年12月30日
http://www.tohoho-web.com/ex/cors.html