CORSについて説明する前に、まず同一オリジンポリシーを理解しましょう。詳細な定義はこちらで参照できます。
同一オリジンポリシーとは、例えばJavaScriptのAJAX(XMLHttpRequestやfetch APIなど)を通じて異なるオリジンからのレスポンスを読み取ることを制限する仕組みです。
オリジンは以下の3つの要素で構成されます:
- プロトコル
- ホスト
- ポート番号
この3つのうちいずれか1つでも異なれば、別のオリジンとみなされます。
例:
-
https://www.facebook.com と http://www.facebook.com
→ プロトコルが異なる(httpsとhttp)ため、別オリジン。 -
https://www.facebook.com と https://www.google.com
→ ホストが異なるため、別オリジン。 -
https://www.facebook.com と https://www.facebook.com:8000
→ ポート番号が異なる(httpsのデフォルトポート番号は443)ため、別オリジン。 -
https://www.facebook.com と https://www.facebook.com/friends
→ パスのみが異なるため、同一オリジン。
では、なぜ同一オリジンポリシーが必要なのでしょうか。
それはセキュリティ上の理由によるものです。
もし同一オリジンポリシーがなかった場合、悪意のあるウェブサイトがAJAXを使ってブラウザのCookieをつけて、例えばGmailのメールデータを取得します。ユーザーが誤ってそのような悪意のあるサイトを訪れてしまうと、そのユーザーのGmailのメールはすべて取得され、内容まで読み取られてしまいます。これは非常に危険です。
実際の開発ではクロスオリジンリクエストが必要になることが多いため、その制限を緩和する仕組みがCORSです。
CORSはCross-Origin Resource Sharingの略で、ブラウザの仕組みの一つです。サーバーがブラウザに対して「どのオリジンからのアクセスを許可するか」を伝えることができます。ブラウザはレスポンスを受け取ると、リクエストを送信したオリジンがサーバーが許可したオリジンに含まれているかを確認します。(この情報はレスポンスヘッダーのAccess-Control-Allow-Origin に含まれます。このヘッダーの値は:特定の1つのオリジンまたは「*」(すべてのオリジンを許可)のいずれかです。)許可されていればJavaScriptはレスポンスを読み取れます。許可されていなければ、ブラウザがブロックし、JavaScriptを使ってレスポンスを読み取ることができません。
上記の説明は単純リクエストの場合です。定義はこちらです。
非単純リクエストでは、以下の流れになります。
-
プリフライトリクエスト(HTTPメソッドはOPTIONSで、ブラウザがAccess-Control-Request-HeadersとAccess-Control-Request-Methodのヘッダーをつける)を送信
-
ブラウザがプリフライトリクエストのレスポンスを確認
ブラウザは以下をチェックします:
a.プリフライトリクエストのオリジンがレスポンスヘッダーのAccess-Control-Allow-Originに含まれているか
b. レスポンスにAccess-Control-Allow-MethodsとAccess-Control-Allow-Headersヘッダーが必要な値を含んでいるか(例えば、非単純リクエストのメソッドがPUT、authorizationヘッダーを含む場合なら、プリフライトレスポンスにはAccess-Control-Allow-MethodsヘッダーにPUTを含んで、Access-Control-Allow-Headersヘッダーにauthorizationを含む必要があります。ただし、メソッドがGET、POST、HEADの非単純リクエストの場合なら、Access-Control-Allow-Methodsヘッダーがなくても問題なくて、あるいはAccess-Control-Allow-Methodsヘッダーがあって、明示的にそのメソッドが書かれていなくても問題ないです。) -
一つ前のステップが問題ないなら、実際のリクエストを送信します。問題があるなら、実際のリクエストは送信されません。
そして、クッキーをつけるクロスオリジンリクエストなら、レスポンスのAccess-Control-Allow-Originヘッダーの値は「*」にできません。必ず明示的にオリジンを指定する必要があります。また、レスポンスにAccess-Control-Allow-Credentials: trueというヘッダーを含む必要もあります。
最後に補足します。CORSはブラウザの仕組みであるため、curlやPostmanなどのブラウザ以外のツールでは影響を受けません。