はじめに
サイオステクノロジーの佐々木千奈です。CORSについて復習したのでまとめ直しました。
自分の今までのCORSについての認識は、なんとなく、別のサーバーからのリクエストを受け付けない設定を行うもの、みたいな認識だったのですが、今年の新卒から「CORSって何ですか?」と聞かれたので今回、慌てて調べなおしました。 自分ははじめ、CORSのことを「コアーズ」と読んでいましたが、「コルス」と読んでいる人が多いようです。
CORSとは
CORSとは、英語でCross-Origin-Resource-Sharingの略です。日本語で訳すと、「異なるオリジン間でのリソース共有」といったところでしょうか。(オリジンについて知らない方は以下の「そもそもオリジンって?」をご覧ください。)
MDNのドキュメントには、以下のように書かれていました。
オリジン間リソース共有 (Cross-Origin Resource Sharing, CORS) は、追加の HTTP ヘッダーを使用して、あるオリジンで動作しているウェブアプリケーションに、異なるオリジンにある選択されたリソースへのアクセス権を与えるようブラウザーに指示するための仕組みです。
そもそもオリジンって?
CORSについて、「異なるオリジン間でのリソース共有」と言われても、オリジンとはそもそもなんでしょう。
こちらもMDNを参照したところ、以下のように書かれていました。
ウェブコンテンツのオリジン (Origin) は、ウェブコンテンツにアクセスするために使われる URL の スキーム (プロトコル)、 ホスト (ドメイン)、 ポート番号 によって定義されます。スキーム、ホスト、ポート番号がすべて一致した場合のみ、 2 つのオブジェクトは同じオリジンであると言えます。
この説明によると、オリジンは、下記の3つの要素で決まります。
スキーム(httpなどのプロトコル部分)+ ホスト(ドメイン) + ポート番号
以下、同一オリジン、異なるオリジンの例です。
同一オリジンの例 (スキーム、ホスト、ポート番号が同じ)
<http://site-a.example.com/>
<http://site-a.example.com:80/>
<http://site-a.example.com/example.html>
異なるオリジンの例
<https://site-a.example.com/> ← スキームが異なる
<http://site-b.example.com/> ← ホストが異なる
<http://site-a.example.com:8080/> ← ポート番号が異なる
同一オリジンポリシーとCORSの関係
同一オリジンポリシーとは、CSRF(クロスサイトリクエストフォージェリ = サイトにまたがるリクエスト偽造)を防止するために、ブラウザが実装している仕組みのことです。これの仕組みにより、ブラウザはデフォルトでは異なるオリジンのリソースへのアクセスを制限しています。
ブラウザに実装された仕組みである同一オリジンポリシーをを一部解除するために用いられる仕組みの一つが、CORSです。
↑ CORSについて色々な説明がありましたが、個人的にはこの説明が一番CORSの説明としてしっくりきました。
CORSの機能
CORSの機能概要について説明します。
CORSは、サーバー側にアクセスを許可するオリジンを定義するAccess-Control-Allow-Origin
というHTTPヘッダーを追加することで作用します。
また、サーバーの情報に副作用を引き起こすことがあるHTTPのリクエストメソッド(特にGET以外のHTTPメソッドや、特定のMIMEタイプを伴うPOST
)に対しては、プリフライトリクエスト(サーバーから対応するメソッドの一覧を収集する)を行い、サーバーの「認可」を得てから実際のリクエストを送信するという仕様もCORSには含まれています。
プリフライトリクエストを発生させないリクエストを、単純リクエストと呼ぶこともあります。
他にも、サーバーはリクエスト時にCookieやHTTP認証などの資格情報を送信するべきかをクライアントに伝える資格情報を含むリクエストを作成することができます。
CORSのシーケンス
CORSの中で最もシンプルな単純リクエストについてのシーケンスを説明します。
例えば、ドメイン http://foo.example
にあるウェブコンテンツが http://bar.other
にあるコンテンツを呼びだす場合について考えます。JavaScriptコードで XMLHttpRequest
を用いてリクエストが送信されると、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>
ここで、CORSに関連するCORSヘッダーは Origin
であり、これは呼び出しが http://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 データ…]
ここで、CORSに関連するCORSヘッダー Access-Control-Arrow-Origin
は Access-Control-Allow-Origin: *
と返しており、そのリソースがすべてのドメインからアクセスできることを示しています。
このサーバーの所有者が、他オリジンからのリソースへのアクセスを http://bar.foo.example
からのリクエストのみに制限したい場合、以下のように送信することで他のオリジンからのアクセスを制限することができます。
Access-Control-Allow-Origin: <https://foo.example>
プリフライトリクエストや資格情報を含むリクエストのシーケンスや、リクエスト/レスポンスのHTTPヘッダーの形式など、もっと詳細を知りたい方は、とほほのwww入門でのCORSについてのページや、CORSに関するMDN記事を参照して下さい。個人的には、とほほ→MDNの順で読むと理解しやすかったです。
最後に
今回は、CORSについてまとめました。改めてCORSについて調べてみることで、CORSについての理解が深まりました。少しでも、「CORSって何?」と思った方の参考になれば幸いです。
それにしても、CORSやCSRF等々、こういった略語って厄介ですよね。Daigoかよ!と思ってしまいます。略語の省略前の姿を知った上で、英語から日本語に訳して初めてスタート地点に立てる感じがします。エンジニアは日々勉強ですが、地道に頑張ります。
参考
- オリジン間リソース共有(MDN) – https://developer.mozilla.org/ja/docs/Web/HTTP/CORS
- Origin(MDN) – https://developer.mozilla.org/ja/docs/Glossary/Origin
- 同一生成元ポリシー(とほほ) – https://www.tohoho-web.com/ex/same-origin-policy.html
- CORS(Cross-Origin Resource Sharing) (とほほ) – https://www.tohoho-web.com/ex/cors.html
- 【備忘録】「CORSってなに?」をできるだけ分かりやすくまとめてみた。 – https://qiita.com/TaikiTkwkbysh/items/ec1f9163d286a94c929d