CORSが鬱陶しい!でも安全のため頑張ってるみたい。
こんにちは、コード苦手な2年目エンジニアです。
Web開発してる時にふとした出会いで「CORS」の赤文字が横切ったので、一旦無視してみたのですが、
「うん、だめだぁ
」
何度やってもAccess to fetched to fetched has been blocked by CORS policy errorとなったので調べてみました。カタカタカタ![]()
「オリジンリソース間共有」「同一オリジンポリシー」「プリフライトリクエスト」
私は、「さて、帰ろうかと思ったのですが」まだ午後3時だったので諦めてCORSの調査に飛び込むことにしました。
そもそもCORSってなに
まず、CORSとは "Cross-Origin Resource Sharing" の略。日本語にすると「クロスオリジンリソース共有」。
一旦、先に進めよう。
実は、Webブラウザには「ごめん、あんたのこと信用してないから、別のサイトの情報は勝手に取っちゃダメ!」っていうセキュリティルールがあるらしい。
このルールが、 「同一オリジンポリシー」
例えば、ネットバンクにログイン中、ひょんなことから開いてしまった悪質なサイトが、裏であなたの口座情報にこっそりアクセスされて「あれ?100円しかない」なんてことが起きるかも?
そんな悲劇を防ぐために、 「見知らぬオリジン(=別のサイト)にはアクセスさせない!」 というガードを固めているわけ(だと思う)。
あれCORSは・・・? 今の話「同一オリジンポリシー」の話でしょ?
でもWebアプリって、フロントエンドはAサーバー、APIはBサーバー、画像はCサーバーとかいろんなところから情報を引っ張ってきて一つの画面に表示するなんてことあるけど![]()
例えば、
- フロントエンドは
https://exampleAAAA.com - APIは
https://api.exmapleBBBB.com - 画像は
https://image.exampleCCCC.jp
これ、全部 「見知らぬオリジン」 だけど、同一オリジンポリシーがガチガチに適用されると、ブラウザは「ンナニコレ?別のサイトじゃん!絶対アクセスさせない!」となってアプリが全く動かなくなるのでは?
ここで、登場するのが CORS
CORSは、ブラウザの固いセキュリティを守りつつも、「このサイトは信用できるやつなんで、特別に情報を共有してあげてくれませんかね?」と、サーバーとブラウザの間に立って取り次ぎをしてくれるらしい。サーバーがCORSに「いいよ!」と許可を出せば、ブラウザも渋々OKしてくれる、ということ。
整理
「同一オリジンポリシー(Same-Origin Policy)」:
別の場所にある情報には勝手にアクセスさせないというルール
「CORS(Cross-Origin Resource Sharing)」:
同一オリジンポリシーという強固なセキュリティを保ちつつも、「信頼できるオリジンからのアクセスであれば、特別に許可してあげよう」 という仕組み
ルール に対して、仕組みによって安全に回避する。
Webアプリケーションのセキュリティと機能性の両立のために、密接に関連して動作しているということらしいですね。
CORSはどうやって動いてるの?
CORSの仕事は、主にブラウザとサーバーの間で行われる 「ヘッダー」 という名刺交換によって決まる。
-
実際にリクエストを送信した時
JavaScriptで別のオリジンにリクエストを送ると、ブラウザは
「私、https://exampleAAAA.comから来ました!」と書かれたOriginという名刺(ヘッダー)をリクエストに渡します。
Origin: https://exampleAAAA.com
これを受け取ったサーバーは、「お、https://exampleAAAA.comさんからか。うちの顧客リストに載ってるから大丈夫だな!」と判断すると、
レスポンスに「https://exampleAAAA.comさん、どうぞどうぞ!」と書かれたAccess-Control-Allow-Originという名刺に許可証を付けて返してくれます。
Access-Control-Allow-Origin: https://exampleAAAA.com
ブラウザはこの名刺を見て、「よし、許可された!」と安心して、あなたにデータを見せてくれるわけです。もしサーバーが名刺を返さなかったり、「あんた誰?」みたいな名刺だったら…
Access to fetched to fetched has been blocked by CORS policy error
赤い文字のあいつが顔を出します。
2.プリフライトリクエスト(Preflight Request)
実は、実際のリクエストを送信する前にそのリクエストが安全かどうか前もってお伺いを立てるリクエストをサーバーに送ってるみたいです。
例えば、DELETEみたいなオラオラなリクエスト飛んできたら一回身構えるじゃないですか。
本番のリクエストを送る前に、「ちょっとお伺い立てますね!」と、ブラウザはまずOPTIONSメソッドという、事前確認用のリクエストをサーバーに送るんです。
これがプリフライトリクエスト。
Origin: https://exampleAAAA.com
Access-Control-Request-Method: DELETE
Access-Control-Request-Headers: Content-Type
サーバーはこれを受け取ると、「ああ、exampleAAAA.comさんがDELETEで使いたいって言ってるのね。了解!」と、許可するメソッドやヘッダーのリストを返してくれます。
Access-Control-Allow-Origin: https://exampleAAAA.com
Access-Control-Allow-Methods: DELETE
Access-Control-Allow-Headers: Content-Type
このお見合いの結果を見て、ブラウザが「うん、大丈夫そう!」と納得したら、初めて本番のリクエストを送ってくれるんです。もし断られたら、はい、またもや赤い文字のあいつの登場です。
もしCORSエラーに遭遇したときは・・・?
CORSエラーに遭遇した時に、調べると多くの人がつまずいてそう。Web開発者にとって一種の通過儀礼?
ここからはあくまで解決した時の体験談だから、一回は確認してみてほしい。
サーバー側の設定ミス:
-
Access-Control-Allow-Originヘッダーに、あなたのフロントエンドのURLがちゃんと入ってますか?まさか*(全許可)のつもりが*(半角アスタリスク)じゃないとか…? -
Access-Control-Allow-Methodsで、使いたいHTTPメソッド(POST とか PUT とか)が許可されてますか? -
Access-Control-Allow-Headersで、Content-Type とか api-key とか、送ってるヘッダーが全部許可リストに入ってますか?
(拡張機能作った時は、ここ見逃してた。気になる人は、https://qiita.com/Kozeni_iranai/items/71f0f336374363b78f75
ポート番号やプロトコルの違い:
-
http://localhost:3000とhttp://localhost:8000はブラウザから見たら「別人」です。ポート番号が違うだけでもCORSエラーになります。 -
http と https の違いも怒られる
「Network」タブ:ここが本丸!OPTIONS リクエストと本番リクエストの両方をクリックして、Request Headers と Response Headers を舐めるように見てください。「Originは送ってるのに、Allow-Originが返ってきてない!」「Request-HeadersにAって書いてるのに、Allow-HeadersにAがない!」など、犯人を見つけやすいかも。
まとめ
CORSは、Webブラウザちゃんの超絶過保護なセキュリティを守りつつ、私たちが安心してWebサービスを利用するための、安全装置なんですね。
-
同一オリジンポリシー:ブラウザの「知らない人とはお話ししない!」ルール
-
CORS:サーバーが「この人は信用できるよ!」とブラウザにお墨付きを出す仕組み
-
動作原理:Origin と Access-Control-Allow-Origin などの 「名刺交換」
-
プリフライトリクエスト:リクエストの前に、「事前お伺い」 を実施
CORSは、もはやWeb開発者の避けて通れないエラー。ただ理解さえしてしまえば、自分が何をすればいいのか見えてくるのではないでしょうか。
この記事が、これからweb開発に挑戦する方や、普段の業務でちょっと息抜きしたいエンジニアの皆さんの参考になれば幸いです。