今更ながらCORSの仕組みについてまとめようと思います
クライアントサイドでJSでプログラム書いている人は、何かしらCORSでのエラーに遭遇したことはあるのではないかと思います。 サーバーサイドでもクライアント側からCORSの設定が〜という依頼は経験したことがあるのかと思います。
私は小さなプロダクトの改修が多いので、クライアントサイドもサーバーサイドも両方対応することがあるのですが、CORSのエラーは 発生したらAPI Gatewayの "CORSを許可する" を設定するように、 今までなんとなく対応して、HTTPプロトコルレベルでどういう仕組みかを真面目に調べたことがなかったので、調べた内容で自分の理解を書いておこうと思います。
ここで記載する内容は、ほとんど以下の内容の抜粋になります。
CORSとは
CORSとは Cross-Origin Resource Sharing の略で、 オリジン間リソース共有と訳されています。私はクロスドメイン制約とか呼ばれていたことを聞いたことがあります。周りでは読み方は "コース" と読まれています。 CORSは ブラウザでOrigin(ドメイン)が異なるリソースへのアクセス許可/拒否できる仕組みです。
ここで1つ注意なのが、ブラウザに課される仕組みなので、 CORSの制約はサーバーサイド間でのやり取りや cURL などのプログラムは影響を受けません。なので、専らCORSの制約の影響を受けるのは ブラウザからXMLHttpRequest または Fetch APIを送る側、もしくはそれを受けるサーバ側ということになります。
アクセス制御パターン
CORSのアクセス制御は以下の2パターンに分かれます。
- 単純リクエストパターン
- CORS プリフライトパターン
単純リクエストパターン
単純リクエストパターンの詳細は要件は以下に記載されていますが、ざっくりいうと GET, HEAD, POST リクエストのうち、特定のHTTPヘッダーとContent-Type
が特定の値の時のみ、単純リクエストパターンとしての制約を受けます。
https://developer.mozilla.org/ja/docs/Web/HTTP/CORS#Simple_requests
単純リクエストの場合、サーバ側からのAccess-Control-Allow-Origin
レスポンスヘッダが "*" もしくは リクエスト送信元のOrigin
と同一であれば、
リクエストが許可され、そうでないと許可されません。
CORS プリフライトパターン
上記のリクエスト条件を満たさないとき、CORSプリフライトパターンの制約を受けます。 CORSプリフライトパターンが必要になる詳細な条件は以下に記載されています。
https://developer.mozilla.org/ja/docs/Web/HTTP/CORS#Preflighted_requests
CORSプリフライトパターンの場合、 初めに OPTIONS
メソッドを送信することが 単純リクエストパターンとは異なります。
初めに OPTIONS
を送信する理由としては、ユーザデータに影響を与える可能性があり、それを事前にチェックするために分けているからです。
プリフライトOPTIONS
リクエストには、リクエストする際に Origin
, Access-Control-Request-Method
と Access-Control-Request-Headers
ヘッダを送信します。
サーバからのレスポンスヘッダに、以下が全て合致していれば許可、そうでなければ拒否となります。
Access-Control-Allow-Origin
レスポンスヘッダが"*" もしくはOrigin
リクエストヘッダと同一Access-Control-Allow-Methods
レスポンスヘッダ にAccess-Control-Request-Method
リクエストヘッダの内容が含まれているAccess-Control-Allow-Headers
レスポンスヘッダ にAccess-Control-Request-Headers
リクエストヘッダの内容が含まれている
CORSで気をつけること
ザクっと概要を書きましたが、CORSを通す上でチェックするポイントしては、以下のような点になります。
クライアント側
- リクエストが単純リクエストパターンなのかプリフライトリクエストパターンなのか区別する。
- 単純リクエストパターンの場合、 レスポンスヘッダの
Access-Control-Allow-Origin
とOrigin
を確認する。 - プリフライトリクエストの場合、
OPTIONS
リクエストへ送られるOrigin
,Access-Control-Request-Method
,Access-Control-Request-Headers
とAccess-Control-Allow-Origin
,Access-Control-Allow-Methods
,Access-Control-Allow-Headers
ヘッダを確認する。- 特に、APIキーなどのシステム固有のヘッダが含まれる場合、そのヘッダが
Access-Control-Allow-Headers
で許可されているか確認することが重要です。
- 特に、APIキーなどのシステム固有のヘッダが含まれる場合、そのヘッダが
サーバ側
Access-Control-Allow-Origin
レスポンスヘッダにアクセスを許可したいドメインを入れる。- プリフライトリクエストパターンのため、
OPTIONS
メソッドのレスポンスを返すことを考慮する。 OPTIONS
レスポンス に 許可したいOrigin, メソッド, ヘッダの設定を入れる。
以上、ざっくり概要のみまとめてみました。詳細は引用元のサイトをみていただければと思います。 CORS普段はフレームワークで設定できることが多いと思いますが、うまく許可が通らなかったり、禁止できなかった場合に、デバッグが必要になると思います。 そうした際に、HTTPプロトコルレベルでどういいった仕組みになっているか理解していると原因の追求が捗るかと思います。