オリジン間リソース共有(CORS)
Cross-Origin Resource Sharing (CORS)
ブラウザの『同一オリジンポリシー(別サイトのデータを勝手に読ませない)』を、安全な範囲で緩めるための仕組み。攻撃ではなく許可の制御。設定を緩めすぎる(特に `*` + credentials)と逆に脆弱になる。
まず大前提: 同一オリジンポリシー
CORSを理解するには、その前提となる制限を先に知る必要があります。ブラウザには 同一オリジンポリシー(Same-Origin Policy) という安全装置があります。
あるサイトのJavaScriptは、別オリジンのサーバから返ってきたデータを勝手に読めない。
『オリジン』とは『スキーム(https) + ドメイン + ポート』の組み合わせ。これが1つでも違えば別オリジンです。
なぜこの制限が必要か? もしこれが無ければ、あなたが開いた悪意あるサイトのスクリプトが、裏で https://あなたの銀行.com/balance を読んで残高を盗めてしまう。『別サイトのデータを勝手に読ませない』——これがブラウザの基本的な守りです。
CORSはこの制限を『緩める』仕組み
ところが現実には、https://app.example.com(フロント)から https://api.example.com(API)を呼びたい、のように正当な理由で別オリジンにアクセスしたいことがよくあります。そこで登場するのが CORS(Cross-Origin Resource Sharing)。
CORSは攻撃ではありません。 サーバが『このオリジンからなら、私のデータを読んでいいですよ』と許可を出すための仕組みです。サーバがレスポンスに Access-Control-Allow-Origin: https://app.example.com というヘッダを付けると、ブラウザは『このオリジンには許可が出ている』と判断して読み取りを通します。
図を描画中...
ここで重要な誤解の解消: CORSはサーバへのリクエスト送信を止めるものではありません。リクエスト自体は届くことがあり、CORSが制御するのは『ブラウザのJavaScriptがレスポンスを読めるか』です。だからCORSはCSRFの対策にはなりません(CSRFはリクエストが届けば成立するため)。
危険な誤設定(ここが本題)
CORSは『緩める』仕組みなので、緩めすぎると逆に穴になります。
Access-Control-Allow-Origin: *と credentials(Cookie送信)の併用:*は『どこからでもOK』。これにCookie付きリクエストの許可を組み合わせると、任意の悪意あるサイトが、ログイン済みユーザーのCookieを使って本人のデータを読める状態になりかねません。(仕様上*と credentials は本来併用できませんが、それを回避しようと下記の反射を使うと危険)- Originヘッダの無検証反射: リクエストに付いてきた
Originの値を、検証せずそのままAccess-Control-Allow-Originにオウム返しする実装。これは事実上『どんなオリジンでも許可』と同じで、最悪です。
正しい設定
必要なオリジンだけを明示的に許可リストに入れる。* やオウム返しではなく、https://app.example.com のように具体的に書く。credentialsを使う場合は特に、許可オリジンを厳密に限定します。
つまずきポイント
- 『CORSはセキュリティ機能?』への正答: 『同一オリジンポリシーという防御を緩和する仕組み。緩めすぎると逆に脆弱になる』。『CORSを設定するとセキュリティが上がる』は誤解。
- CORSとCSRFは別物。CORSは『レスポンスを読めるか』の制御、CSRFは『リクエストが届いて実行されてしまう』問題。CORSを設定してもCSRFは防げない。
- CORSエラーは『攻撃を防いだ証拠』のこともあれば、単なる設定ミスのことも。開発中に出るCORSエラーは、たいてい許可オリジン設定の不足。むやみに
*で潰さず、正しいオリジンを許可する。
📊 図解
preflight から本リクエストまで(シーケンス図)
ブラウザが OPTIONS で事前確認し、サーバの許可ヘッダを見て本リクエストを送ります。
図を描画中...