CORS
CORS (Cross-Origin Resource Sharing)
概要(サマリー)
CORS(Cross-Origin Resource Sharing)とは、別の場所にあるサーバーのデータを、ブラウザが安全に使ってよいか確認する仕組みである。初心者向けには「ブラウザが勝手に外部のデータを読みに行かないようにする門番」と考えるとわかりやすい。たとえば、画面側のアプリが http://localhost:3000 で動いていて、APIが http://localhost:8000 にある場合、ブラウザは「これは別の場所へのアクセスだ」と判断する。このとき、API側が許可を出していないと「CORSエラー」になる。
詳細解説
CORSを身近な例で考える
Webアプリでは、画面を表示する場所とデータを持っている場所が別々になることがある。たとえば、画面は自分のパソコン上で動かし、ユーザー情報は別のAPIから取得するような作りである。
このとき、ブラウザはすぐにデータを渡してくれるわけではない。「この画面は、そのAPIのデータを読んでよいのか」を確認する。API側が「この画面からのアクセスは許可します」と答えれば通信できる。許可がない場合、ブラウザが止める。これがCORSエラーである。
つまりCORSは、フロントエンドとバックエンドを別々に動かすときによく出てくる、ブラウザ側の安全確認だと考えるとよい。
オリジンとは何か
CORSを理解するには、「オリジン」という言葉を押さえておく必要がある。オリジンとは、URLのうち「プロトコル・ドメイン・ポート番号」の組み合わせのことである。
| URL | オリジン |
|---|---|
https://example.com/page |
https://example.com |
http://example.com/page |
http://example.com(上とは別) |
https://example.com:8080/page |
https://example.com:8080(上とは別) |
このように、プロトコルやポートが1文字でも違えば「別のオリジン」と見なされる。
たとえば、次の2つはどちらも localhost だが、ポート番号が違うため別オリジンである。
http://localhost:3000http://localhost:8000
初心者がローカル開発でCORSエラーに遭遇しやすいのは、この「ポート番号が違うだけでも別扱いになる」という点が原因であることが多い。
なぜブラウザは通信を止めるのか
ブラウザには「同一オリジンポリシー(Same-Origin Policy)」という安全のためのルールがある。これは、あるWebページが別のオリジンのデータを勝手に読み取れないようにする仕組みである。
もしこの制限がなければ、悪意あるサイトが別サービスのデータを勝手に読もうとする危険がある。たとえば、ログイン中のサービスに対して、別の怪しいページが裏側でアクセスし、その結果を読み取ろうとするような攻撃が考えられる。
そのため、ブラウザは別オリジンへの通信に慎重である。サーバー側が明示的に許可している場合だけ、ブラウザはそのレスポンスをJavaScriptから使えるようにする。
サーバー側が「許可します」と伝える
CORSでは、サーバー側がHTTPヘッダーで「このオリジンからのアクセスは許可します」と伝える。代表的なヘッダーは次のようなものである。
Access-Control-Allow-Origin: https://example.com
Access-Control-Allow-Methods: GET, POST, PUT, DELETE
Access-Control-Allow-Headers: Content-Type, Authorization
特に大事なのは Access-Control-Allow-Origin である。これは「どのオリジンからのアクセスを許可するか」を示す。
たとえば、次のように書かれていれば、https://example.com からのアクセスは許可される。
Access-Control-Allow-Origin: https://example.com
一方で、この設定がない、またはアクセス元と一致していない場合、ブラウザはレスポンスをJavaScriptに渡さず、CORSエラーとして扱う。
CORSエラーが出たときの対処
ブラウザのコンソールに CORS policy という文字が出たら、CORSエラーの可能性が高い。このエラーで大事なのは、「APIが完全に壊れている」とは限らないことである。サーバーから応答が返っていても、ブラウザが「この画面には読ませない」と判断して止めている場合がある。
基本的な確認順は次のとおりである。
- 呼び出しているAPIのURLが正しいか確認する
- フロントエンドとAPIのオリジンが違っているか確認する
- API側にCORSの許可設定があるか確認する
- 許可しているオリジンが、実際のアクセス元と一致しているか確認する
- Cookieや認証情報を送っている場合は、その設定も確認する
多くの場合、直す場所はフロントエンドの fetch の書き方ではなく、API側のCORS設定である。ただし、JavaScript側で不要なヘッダーを付けていたり、認証情報の送り方がサーバー側の設定と合っていなかったりする場合もある。
* で全部許可すればよいわけではない
Access-Control-Allow-Origin: * と書くと、「どのオリジンからのアクセスも許可する」という意味になる。学習用や公開データを返すだけのAPIでは使われることがある。
しかし、ログイン中のユーザー情報や個人データを扱うAPIで、何でも * にしてよいわけではない。特にCookieなどの認証情報を含む通信では、* は使えない場合がある。セキュリティ上も、本番環境では必要なオリジンだけを明示的に許可するほうが安全である。
初心者のうちは、「CORSエラーが出たから * にする」と覚えるのではなく、「どの画面からのアクセスを許可したいのかをサーバー側に教える」と考えるほうがよい。
AIコーディングとの関係
AIが生成した画面側のコードと、別に立てたバックエンドのAPIを接続しようとしたとき、CORSエラーはよく発生する。AIに相談するときは、単に「CORSエラーです」と言うより、次の情報を一緒に渡すとよい。
AIは、Express、Laravel、Django、FastAPIなど、使っている環境に合わせたCORS設定例を提案できる。ただし、AIが * で全許可するコードを出すこともあるため、本番環境では許可するオリジンを絞るように確認することが大切である。
よくある勘違い
CORSエラーはフロントエンドのコードが原因?
多くの場合、原因はサーバー側のCORS設定にある。ただし、フロントエンド側で不要なヘッダーを追加していたり、認証情報を送る設定がサーバー側と合っていなかったりすることもある。まずはブラウザのコンソールと、実際に呼び出しているURLを確認するとよい。
Access-Control-Allow-Origin: * にすれば全部解決する?
解決しない場合がある。* はすべてのオリジンを許可する指定だが、認証情報を含む通信では使えないことがある。また、本番環境で何でも許可すると、不要な場所からのアクセスまで許してしまう。基本は、必要なオリジンだけを指定する。
CORSはサーバー間通信でも発生する?
基本的には発生しない。CORSはブラウザの安全機能であるため、Node.jsやPythonなどのサーバー同士が通信する場合には制限されない。CORSが問題になるのは、主にブラウザ上のJavaScriptが別オリジンのAPIを呼び出す場面である。
APIが壊れているという意味?
必ずしもそうではない。API自体は正常に応答していても、ブラウザがそのレスポンスをJavaScriptに渡さないことがある。CORSエラーを見たら、「APIが落ちている」と決めつけず、「ブラウザが読み取りを止めている可能性がある」と考えると原因を探しやすい。
まとめ
- CORSは、ブラウザが別オリジンのリソースを安全に使ってよいか確認する仕組みである。
- オリジンは、プロトコル、ドメイン、ポート番号の組み合わせで決まる。
- CORSエラーは、APIが壊れているという意味ではなく、ブラウザがレスポンスの利用を止めている場合がある。
- 本番環境では
*で全許可するのではなく、必要なオリジンだけを許可する設計が重要である。 - AIに相談するときは、フロントエンドURL、API URL、エラー全文、認証情報の有無を伝えると原因を絞り込みやすい。
情報ソース
より詳しくAIに聞いてみよう
- CORSとは何かを、初心者でもわかるように説明してください。
- ブラウザの同一オリジンポリシーがなぜ必要なのか、セキュリティの観点から教えてください。
- Node.js(Express)でCORSを設定する具体的なコードを教えてください。
Access-Control-Allow-Origin: *を本番環境で使ってはいけない理由を教えてください。- AIコーディングでフロントエンドとバックエンドを接続するときのCORSエラーの解決手順を教えてください。