Rso's Jotter

日々の開発の知見のメモやその他雑記

今更ながらCORSの仕組みについてまとめようと思います

クライアントサイドでJSでプログラム書いている人は、何かしらCORSでのエラーに遭遇したことはあるのではないかと思います。 サーバーサイドでもクライアント側からCORSの設定が〜という依頼は経験したことがあるのかと思います。

私は小さなプロダクトの改修が多いので、クライアントサイドもサーバーサイドも両方対応することがあるのですが、CORSのエラーは 発生したらAPI Gatewayの "CORSを許可する" を設定するように、 今までなんとなく対応して、HTTPプロトコルレベルでどういう仕組みかを真面目に調べたことがなかったので、調べた内容で自分の理解を書いておこうと思います。

ここで記載する内容は、ほとんど以下の内容の抜粋になります。

developer.mozilla.org

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-MethodAccess-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-OriginOriginを確認する。
  • プリフライトリクエストの場合、 OPTIONS リクエストへ送られる Origin, Access-Control-Request-Method, Access-Control-Request-HeadersAccess-Control-Allow-Origin, Access-Control-Allow-Methods, Access-Control-Allow-Headersヘッダを確認する。
    • 特に、APIキーなどのシステム固有のヘッダが含まれる場合、そのヘッダが Access-Control-Allow-Headers で許可されているか確認することが重要です。

サーバ側

  • Access-Control-Allow-Originレスポンスヘッダにアクセスを許可したいドメインを入れる。
  • プリフライトリクエストパターンのため、OPTIONSメソッドのレスポンスを返すことを考慮する。
  • OPTIONS レスポンス に 許可したいOrigin, メソッド, ヘッダの設定を入れる。

以上、ざっくり概要のみまとめてみました。詳細は引用元のサイトをみていただければと思います。 CORS普段はフレームワークで設定できることが多いと思いますが、うまく許可が通らなかったり、禁止できなかった場合に、デバッグが必要になると思います。 そうした際に、HTTPプロトコルレベルでどういいった仕組みになっているか理解していると原因の追求が捗るかと思います。