こんにちは!
気になったことがあったらとことん調べたくなる富田です。
今回は、WEBを扱っているエンジニアがなんだかんだ1度は遭遇するであろうCORSエラーについて、「そもそも、何のためにあるんだ?」という切り口でちょっと調べてみたという記事になります。
なんとなく触ってるけど、CORSってなんだ?
CORSエラーというと、WEBアプリケーションを作ったことのある人なら一度は遭遇したことがあるのではないでしょうか?いつも「なんとなく調べて、こうすれば直ると知って修正したらよくわからんどちゃんと動いた~!」ってなりがちな気がします。しかし、よくよく考えると、あれはいったい何でしょうか???よくわからなくなってきたので、調べてみました。
MDNにはこんなことが書いてありました。
Cross-Origin Resource Sharing (CORS) is an HTTP-header based mechanism that allows a server to indicate any origins (domain, scheme, or port) other than its own from which a browser should permit loading resources.
なるほどわからん。
とにかく、サーバーがoriginなるものに対して、リソースの読み込みの許可を示すことをできるようにする仕組みのようです。originは(domain, scheme, or port) とあるので、ドメイン名、スキーム(httpやhttpsといったプロトコルのことのようです)、ポート番号の組のことで、つまり、サーバがブラウザに対して通信をしていい相手を指定しているようです。
なぜ、そんなことをしているのでしょうか?
背景にあるのはSame-origin policy
もう少し読み進めてみると、こんなことが書いてありました。
For security reasons, browsers restrict cross-origin HTTP requests initiated from scripts. For example,
XMLHttpRequest
and the Fetch API follow the same-origin policy.
cross-origin HTTP requestとは、WEBサイトのスクリプトが自身のorigin以外のoriginに送るHTTPリクエストのことです。どうやらブラウザはセキュリティ上の理由によりWEBサイトのスクリプトが他の通信相手にHTTPリクエストを送ることを制限しているようです。
なぜ制限しているのでしょうか?制限することがセキュリティとどう関係するのでしょうか?答えはsame-origin policyの説明にありました。
It helps isolate potentially malicious documents, reducing possible attack vectors. For example, it prevents a malicious website on the Internet from running JS in a browser to read data from a third-party webmail service (which the user is signed into) or a company intranet (which is protected from direct access by the attacker by not having a public IP address) and relaying that data to the attacker.
ブラウザを踏み台にして社内のネットワークやログインしているサービスに不正アクセスされるのを防ぐためのようです。same-origin policyが無いと、下の図のようにブラウザを踏み台にしてログイン済みのメールサービスやプライベートネットワークにあるサーバなどアクセスされたくないリソースから情報を抜き取る悪意のあるスクリプトが書けてしまいます。このような事を防ぐために、WEBサイトのスクリプトは自身のorigin以外との通信を禁じていて、それがSame-origin policyということのようです。
Same-origin policyの例外がCORS
セキュリティのためにWEBサイトのスクリプトが自身のorigin以外と通信できないのはわかりました。しかし、自身のorigin以外と通信できないとしばしば困るパターンがありませんか?例えば、フロントエンドとバックエンドが別サーバで、フロントエンドのスクリプトがバックエンドに通信しないといけない場合ってあると思います。あと、第三者が公開しているWebAPIを叩きたい場合もありますよね?そういう場合にSame-origin policyがあると困ると思います。では、どうしているのでしょうか?
結論から書くと、通信先のサーバがそのOriginを許可した場合に限り例外的に通信できるようにするということのようです。先の悪意のあるWEBサイトの例で、想定していないスクリプトがサーバーにアクセスしているという共通点に注目すると、サーバ側で想定しているスクリプトすなわちoriginを決めて、それ以外はアクセスできないようにしたら、問題を防ぎつつWEBサイトに他のサーバへのアクセスを提供することができそうです。つまり、サーバ側が個別に設定するSame-origin policyに例外を定めて、WEBサイトが他のリソースも扱えるようにするための仕組みがCORSのようです。
実際には、下の図のように、サーバがOrigin単位で許可した返答を返して、ブラウザ側でそれをスクリプトに渡してよいか判定するようです。
まとめ
WEBアプリケーションの開発でしばしば遭遇するCORSエラーですが、調べてみたらその背景には、悪意のあるサイトがブラウザを踏み台にできないようにするというセキュリティ上の課題があったことが分かりました。そして、そのためにサーバー側がoriginを定めてそのoriginのみと通信をするようにするという解決策が用いられていることが分かりました。
CORSエラーが発生した時に、まずバックエンド側の設定を見るのはこういうことだったわけですね。