当サイトは、アフィリエイト広告を利用しています

CORSの発生原因とその対応についてわかりやすくまとめてみた

作成日:2024月04月03日
更新日:2024年04月03日

今までの開発でよくCORSがでて、通信ができないことが多々あったが
適当に調べて、対応していた。

どういう仕組みなのかについてちゃんと調べてみたので
忘備録として残しておく。

CORSに関する用語

CORSをまとめるにあたって、まずはCORS界隈の用語を整理しておく

オリジンとは?

CORSをまず調べて最初にでてくるのが

  • オリジン間リソース共有

である。

はい、もうよくわからんってなるのでまずはオリジンから。

オリジンは次の3つの要素から構成される

ドメイン(Domain)

インターネット上のリソースを特定するための識別子のこと このブログでいうところの"scrawledtechblog.com"

プロトコル(Protocol)

ウェブブラウザーがリソースにアクセスする方法のこと
HTTPとかHTTPSのこと
※FTPやWebSocketなどもある

ポート番号(Port Number)

サーバー上で待ち受ける接続のポイントのこと。
ローカルで開発する時に「localhost:5000」とかでサーバーアクセスするが
この5000部分のこと。

オリジンはドメイン、プロトコル、ポート番号の組み合わせで構成される。

同一生成元ポリシー(Same Origin Policy)とは?

これもよく見る。

同一生成元ポリシー (Same-Origin Policy) はウェブブラウザのセキュリティ機能の一つで
Webページを生成したドメイン以外へのHTTPリクエストができないようになっている。

SPA(Single Page Application)などの場合は、基本的にサーバーが二つある

  • ブラウザからのリクエストに対してWEBページを作って返しているWEBサーバー
  • クライアントに表示されたWEBページからの非同期リクエスト対して応答しているAPIサーバー

この場合、WEBサーバーとAPIサーバーは別のオリジンなのでブラウザが
クロスオリジン(異なるオリジン)のリクエストをブロックする。 2024-04-03-23-22-37

CORSって何?

関連用語が分かったところでCORSについてまとめる。

CORSは正式にはCross-Origin Resource Sharing。オリジン間リソース共有ともいう。
これはウェブページが異なるオリジンからデータを安全に取得できるようにするための仕組み
※具体的にはブラウザに対してクロスオリジンの通信を許可するための仕組み

ブラウザは同一生成元ポリシーによってクロスオリジンの通信を制限するので
クロスオリジンであっても安全に通信できるようにブラウザに指示することをCORSという

ちなみにブラウザを介さずにAPI間で直接通信を行う場合、CORSは関与しないので、CORSによるエラーや制限を心配する必要はない

CORSはどうやって実現しているのか?

SPA(Single Page Application)で作られたアプリケーション(クロスオリジンのサーバーがある)を例にして
CORSの仕組みを使って説明してみる。

下記のような異なるオリジンだとする

  • ブラウザからのリクエストに対してWEBページを作って返しているWEBサーバー  :https://myapp.example.com
  • クライアントに表示されたWEBページからの非同期リクエスト対して応答しているAPIサーバー :https://api.example.com

フロントエンドアプリケーションからリクエスト送信

ユーザーはブラウザでWEBサーバーにアクセスして
WEBページを開く。

そして何らかの操作により、JavaScriptを使用して、異なるオリジンのAPIサーバーに
リクエストが送信される

ブラウザのCORSチェック

ブラウザは、このリクエストが同一オリジンポリシーに違反しないかどうかをチェックする
異なるオリジンへのリクエストであるため、ブラウザはCORSプロトコルに従って動作する

クロスオリジン仕様の動きになる

プリフライトリクエスト送信

ブラウザは、実際のリクエストを送信する前に「プリフライトリクエスト」をAPIに送信する
これはOPTIONSメソッドを使用したリクエストで、実際のリクエストが安全に送信できるかどうかを確認するために行う。

APIサーバーのCORS設定

APIサーバーは、プリフライトリクエストを受け取り、設定されたCORSポリシーに基づいてレスポンスを返す。
このレスポンスには

  • Access-Control-Allow-Origin`ヘッダー(許可されるオリジンを指定)
  • Access-Control-Allow-Methods`ヘッダー(許可されるHTTPメソッドを指定)

などが含まれる。

ブラウザのレスポンスチェック

ブラウザは、APIからのレスポンスを受け取り、CORSヘッダーをチェックする
Access-Control-Allow-Origin`ヘッダーにフロントエンドアプリケーションの
オリジン( https://myapp.example.com )が含まれていれば、リクエストは成功となる。

詳しくは後述するが、APIサーバーのCORS設定していた場合、APIサーバー側でクロスオリジンの
許可リストをもっていて、( https://api.example.com )がリストにあれば、Access-Control-Allow-Origin`ヘッダーをつけて返すイメージ。

実際のリクエストの送信

プリフライトチェックが成功した場合、ブラウザは実際のリクエストをAPIサーバーに送信する。

データの取得

APIサーバーはリクエストに対するレスポンスをブラウザに送信する。
このレスポンスにもCORSヘッダーが含まれている必要がある。
ブラウザは再度CORSヘッダーをチェックし、問題がなければJavaScriptコードにデータを提供する

CORSエラーはどういう意味か?

ここまでの説明からCORSが発生したということは原因としては

  • ブラウザがクロスオリジンのリクエストを投げている
  • リクエストを受けたサーバー側がCORS設定を行っていない

になる。

サーバー側のCORS設定方法について

上記のフローでわかる通り、CORSの設定はAPIサーバー側で設定する必要がある。

許可リストの設定

APIサーバーは、どのオリジンからのリクエストを許可するかを設定する
これは通許可リスト(whitelist)として管理され、許可リストには、
ブラウザからのリクエストに対してWEBページを作って返している
WEBサーバーのオリジン(例:https://myapp.example.com )を入れるようにする。

クロスオリジンからのリクエストが許可リストにあれば
APIサーバーはレスポンスにAccess-Control-Allow-Originヘッダーを入れてレスポンスするので
通信できるようなる

どこでCORS設定するの?

CORSの設定はAPIサーバー側で設定すると書いたが基本的にはサーバーアプリケーション内で行うことが多い。
だが、場合によってはサーバー自体がCORSを制御することもある。

サーバーアプリケーション内で設定する場合

一般的には、Flask、Django、Express.jsなどのWebフレームワークを使用している場合、
アプリケーションのコード内でCORS設定を行う。

Flaskとかだとそのためのライブラリ(flask-cors)がある。
下記はflaskで全てのオリジンを許可する設定

flaskの対応例
from flask import Flask, request
from flask_cors import CORS
# flaskインスタンス作成
api = Flask(__name__)
# CORS対応
CORS(api)

これにより、特定のオリジンからのリクエストを許可できます。

サーバー自体がCORSを制御する場合

WebサーバーソフトウェアのNginx、Apacheは、サーバー自体でCORS設定を行うことができる。
これは、リバースプロキシやロードバランサーを使用している場合にメリットがある。

サーバー自体でCORSを制御する場合、アプリケーションのコードを変更せずにCORSポリシーを適用できる

まとめ

CORSについてちゃんと調べてみたら
仕組み自体はそこまで複雑ではなかった。
※実際に対応するとなると別のかもしれないが。

CORSが出る原因と対応方針がわかったので
もうCORSを怖がらずやっていけそう。

参考

新着記事

top