はじめに
こんにちは、エンジニアのkeitaMaxです。
CORSについて曖昧な理解のままだったので、一度しっかり整理しようと思い、この記事を書きました。
CORSとは
オリジン間リソース共有 (Cross-Origin Resource Sharing, CORS) は、 HTTP ヘッダーベースの仕組みを使用して、あるオリジンで動作しているウェブアプリケーションに、異なるオリジンにある選択されたリソースへのアクセス権を与えるようブラウザーに指示するための仕組みです。
(引用;https://developer.mozilla.org/ja/docs/Web/HTTP/Guides/CORS)
CORSとは、異なるオリジン間でブラウザがアクセス制御を行う仕組みです。
ブラウザには「同一オリジンポリシー」というセキュリティ制約があり、
- プロトコル(http/https)
- ドメイン
- ポート番号
のいずれかが違うと、JavaScriptから自由にデータを取得できません。
サーバーは普通にレスポンス返してるが、ブラウザが制御してJavaScriptにデータを渡さない仕組みのことです。
CORSはどうやって実現されるのか
流れとしては以下のような感じです
- ブラウザがAPIへリクエストを送る
- APIサーバーがレスポンスにCORSヘッダーを付与する
- ブラウザがヘッダーを確認する
- 許可されていればレスポンスをJavaScriptに渡す
Access-Control-Allow-Origin: https://example.com
上のようなヘッダーがあると、https://example.comからのデータをブラウザはJavaScriptに渡すことができます。
CORSエラーについて
フロント開発をしているとよくCORSエラーに遭遇すると思います。
これはサーバー側のCORS設定が適切でない場合に発生します。
つまり、APIレスポンスに
Access-Control-Allow-Origin: {自分のオリジン}
がない場合、ブラウザがブロックします。
サーバ側の設定で許すオリジンをあらかじめ設定しておかなくてはいけません。
多くの場合はCORS設定不足のために起こっています。
ただ、CORS設定をしたのにAccess-Control-Allow-Originが返却されていないか、Access-Control-Allow-Originに使用したいオリジンを設定していないかだと思います。
ただ、CORSを設定していてもCORSエラーが出る場面に出会ったことがあるので、それを簡単に記載します。
サーバーエラー時にCORSヘッダーが付かない
API内部でエラーが発生し、サーバーがデフォルトのHTMLエラーページを返す場合があります。
この場合
- CORSヘッダーが付かない
- ブラウザはCORSエラーとして表示
実際はCORSではなくサーバーエラーということになってしまいます。
アプリケーション到達前にブロックされている
例えば
- Cloudflare / WAF
- nginx設定ミス
- CDNの制限
などでブロックされた場合です。
アプリまで届かないためCORSヘッダーが付かず、結果としてCORSエラーに見えます。
CORSエラーでもサーバーは処理をする
ここは誤解しやすいポイントがあります。
CORSはブラウザの制御機能なので、
- サーバーは普通にリクエストを処理する
- レスポンスも返す
- ただしブラウザがJSに渡さない
という挙動になります。
つまりこれだけの機能だと、不正なPOSTでもサーバー側では実行される可能性があります。
そこでCORSにはプリフライトという機能があります。
プリフライトについて
CORSの機能の一部にプリフライトというものがあります。
これは以下のような場合などに行われます
- PUT / PATCH / DELETE などのメソッド
- Authorizationヘッダー付きリクエスト(シンプルリクエスト条件を満たさない)
- application/json など特定Content-Type
流れは次の通りです。
- JSがPUTなどのリクエストを要求
- ブラウザがOPTIONSリクエストを先に送る(プリフライト)
- サーバーが許可ヘッダーを返す
- 問題なければ本リクエスト送信
もしプリフライトで許可されなければ、4でCORSエラーとなり、本リクエストが送信されることはありません。
つまり、プリフライトで許可されなかった場合、PUT/DELETEなどの更新系リクエストや、Cookie・Authorizationヘッダー付きリクエストもブラウザからは送信されません。
※ クロスオリジンの場合、fetch(url, { credentials: "include" })ないとCookieは送られないです
※ また、Cookieを利用する場合、CORS設定とは別に SameSite 属性の設定も必要になります。それはまた他の記事で書こうかと思っています。
ただしこれはブラウザの制御に過ぎないため、curlなどからは通常通りリクエスト可能です。
CORSはセキュリティ対策ではない点には注意が必要です。
おわりに
CORSはよく見るエラーですが、曖昧なまま来てしまっていたのでしっかり調べる機会をとって良かったと思います
この記事での質問や、間違っている、もっといい方法があるといったご意見などありましたらご指摘していただけると幸いです。
最後まで読んでいただきありがとうございました!
参考