はじめに
とある開発において、DEV環境はWEBサイトからAPIがコールできるのに、STG環境は出来ないよ!っていう問題の調査をしたときに調査したことのまとめです。
結論は単純な環境差異で、STG環境ではAccess-Control-Allow-Origin
が付与されていませんでした。
CORSについておさらい。
CORSの用途や目的をAIさんにまとめてもらいました!
1. セキュリティの強化:
- 異なるオリジン間のリソース共有を制御し、不正なクロスサイトリクエストを防止します。
- 信頼できるドメインからのアクセスのみを許可し、悪意のあるウェブサイトからのデータ取得を制限します。
2. ブラウザの同一オリジンポリシーの制限緩和:
- 異なるドメイン、プロトコル、ポートからのリソースアクセスを可能にします。
- 開発者が複数のドメインにまたがるWebアプリケーションを構築できるようにします。
3. APIの利用制御:
- 特定のクライアントドメインに対してのみAPIアクセスを許可します。
- APIの使用を認可されたウェブサイトやアプリケーションに限定できます。
4. マイクロサービスアーキテクチャの支援:
- 異なるドメインでホストされている複数のサービス間の通信を可能にします。
- フロントエンドとバックエンドを分離した開発を促進します。
5. サードパーティサービスの統合:
- 外部APIやサービスとの安全な統合を実現します。
- CDNやクラウドストレージなど、異なるドメインのリソースの利用を可能にします。
6. 開発環境と本番環境の分離:
- 開発中のフロントエンドアプリケーションが本番環境のAPIにアクセスすることを可能にします。
7. モバイルアプリケーションのサポート:
- WebViewを使用するモバイルアプリケーションが、異なるドメインのAPIにアクセスできるようにします。
8. ユーザーエクスペリエンスの向上:
- シングルページアプリケーション(SPA)など、動的なコンテンツ読み込みを可能にします。
- クロスドメインでのAjaxリクエストを実現し、ページのリロードなしでデータを取得できます。
9. コンプライアンスと監査:
- リソースへのアクセスを制御し、監査可能にすることで、規制要件への準拠を支援します。
10. レガシーシステムの統合:
- 新しいウェブアプリケーションと既存のバックエンドシステムを安全に統合することができます。
これらの点から、CORSは現代のWeb開発において、セキュリティを維持しつつ柔軟なアプリケーション構築を可能にする重要な仕組みとなっています。
構成
環境はCloudfront+APIGateway+NLB+EC2の構成です。
(この記事執筆のための検証はAPI Gatewayの背後はMock統合になっています。)
悩みどころ。
PostmanでAPI叩いても、Access-Control-Allow-Origin
が付与されない。
すぐに問題解決はしたのですが、PostmanでそれぞれDEV/STG環境の同APIの挙動を確認しても、レスポンスヘッダに有意義な違いを見つけることができず、ここに時間を要してしまいました。
原因はOrgin
ヘッダーが付与されているかどうかの違いでした。
-
Orgin
ヘッダーがない場合
-
Orgin
ヘッダーがある場合
今回はCloudFrontにCORSヘッダを付与する設定をいれていますが、Orginヘッダーが付与された場合のみ、Access-Control-Allow-Origin
を付与するみたいです。
少し、Orginヘッダについて調べると、以下の条件時にブラウザが自動で付与する模様です。(例外もあるので、詳細はリンク先をご確認ください!)
- オリジン間リクエスト
- GETまたはHEAD以外の同一オリジンリクエスト
なお、オリジン=ドメインではなく、オリジンは、プロトコル、ポート番号 (もしあれば)、ホストの3つを含めてオリジンと呼ぶらしいです。
どこで設定すればいいのか。
今回はCloudFrontで設定しましたが、CORSヘッダの付与はいくつかの箇所で設定可能です。
単純リクエスト用にCloudFront、プリフライトリクエスト用にAPI Gateway、といった設定がいいのかなといった所感です。
CloudFront
シンプルに設定するなら、ビヘイビアのレスポンスヘッダーポリシーからAmazonマネージドポリシーを使うのが良いと思います。
細かな設定をする場合は、以下のような対応が必要そう。
- カスタマーポリシーを作成
- Lambda@edgeや、CloudFrontFunctionsを使い、コードで設定を行う。
API Gateway
統合レスポンスを設定することで、任意のヘッダを付与することも可能。
CORS目的ではなく、その他汎用的な使い方な気がする。
CORSに限定すると、リソースのところからも設定が可能だけど、こっちはプリフライトリクエスト用かな。
実際に有効化すると、OPTIONSリクエストができるようになります。
EC2(Apache等)
設定方法は割愛しますが、Apahce等のミドルウェアやその上位のアプリケーションで付与することも可能。
だた、変更があるたびに資材のデプロイが発生するので、あえてここでする必要はないかな。
まとめ
うすーく理解していたCORSですが、今回のトラブルを機に少し理解が深まりました!