目次
CORS(クロスオリジン・リソース・シェアリング)完全解説
〜なぜエラーが起きるのか、どんな意味があるのか〜
はじめに
みなさん、フロントエンド開発をしていて「CORSエラー」という赤文字に悩まされたことはありませんか?
自分で作ったAPIなのに、XMLHttpRequest (XHR)
や fetch
でアクセスすると「Access-Control-Allow-Originが設定されていない」とエラーになる。そんな経験をした方は多いと思います。
💡 よくある場面: ローカル開発でhttp://localhost:3000
からhttp://localhost:5000
のAPIにアクセスしようとして、突然CORSエラーが発生する。
今日はこの CORS(Cross-Origin Resource Sharing, クロスオリジン・リソース・シェアリング) について、順を追って学んでいきましょう。
この記事で学べること
1. そもそも「オリジン」とは?
まずCORSを理解する前に、「オリジン」という言葉を押さえましょう。
オリジン(origin) とは、Web上での「出所(プロトコル・ドメイン・ポートの組み合わせ)」を指します。
オリジンの構成要素
オリジンは以下の3つの要素で構成されています:
1. プロトコル(http/https)
2. ドメイン(example.com)
3. ポート番号(:80, :443, :3000など)
具体例で理解する
例を挙げると:
https://example.com:443
http://example.com:80
https://api.example.com:443
これらは、たとえ同じ「example.com」でもプロトコルやポートが違えば別オリジンとして扱われます。
🎯 重要: ブラウザはこの3つの組み合わせが完全に一致する場合のみ「同一オリジン」と判断します。
2. なぜCORSという仕組みが必要なのか?
ここで質問です。
もしブラウザが制限なくどんなサイトのリソースにもリクエストできるとしたら、何が起きるでしょうか?
想定される危険なシナリオ
シナリオ1: 悪意あるサイトからの攻撃
1. 悪意あるサイトにアクセスしたユーザーのブラウザが、自動的にユーザーの銀行サイトへリクエストを飛ばす。
→ ユーザーがログイン済みなら、そのCookie情報が勝手に送信されてしまう。
2. ユーザーが気づかないうちに、個人情報や決済情報が外部に流出する。
シナリオ2: データの不正取得
同一オリジンポリシーの役割
こうした クロスサイトリクエストフォージェリ(CSRF) 的な攻撃を防ぐために、ブラウザは「同一オリジンポリシー(Same-Origin Policy)」というルールを守ります。
🛡️ 同一オリジンポリシー: 自分のオリジン以外に対しては勝手に通信しない
しかし困ることもある
しかし実際には、フロントエンド(https://myapp.com
)とAPIサーバー(https://api.myapp.com
)が別オリジンになるケースはよくあります。
このままでは正しい通信すらブロックされてしまう…。
そこで登場したのが CORS です。
💡 CORSの役割: サーバーが「このオリジンからのアクセスは安全です」とブラウザに伝える仕組み
3. CORSの仕組み
CORSは、サーバーが「このオリジンからのアクセスはOKですよ」とブラウザに伝える仕組みです。
基本的な流れ
1. フロントエンドが別オリジンのAPIにリクエストを送信
2. ブラウザが「この通信は安全?」とサーバーに確認
3. サーバーが「このオリジンは許可します」と返答
4. ブラウザが通信を許可
重要なHTTPヘッダー
そのための代表的なHTTPヘッダーがこちら:
Access-Control-Allow-Origin: https://myapp.com
これが返ってくれば、ブラウザは通信を許可します。
逆に書かれていなければ「CORSエラー」となります。
その他の重要なヘッダー
Access-Control-Allow-Methods: GET, POST, PUT, DELETE Access-Control-Allow-Headers: Content-Type, Authorization Access-Control-Allow-Credentials: true
✅ 成功の条件: サーバーが適切なCORSヘッダーを返すことで、ブラウザが通信を許可します。
4. プリフライトリクエストとは?
ここでよく疑問に思われるのが「プリフライトリクエスト」です。
これは 事前確認のリクエスト のことです。
プリフライトが必要な場合
プリフライト不要(シンプルリクエスト)
GET
メソッドHEAD
メソッド POST
メソッド(特定の条件のみ)プリフライト必要(複雑なリクエスト)
PUT
DELETE
など「副作用のある」メソッドContent-Type: application/json
などプリフライトの流れ
このときブラウザは、まず以下のような OPTIONS
リクエストをサーバーに送ります:
OPTIONS /api/data HTTP/1.1 Origin: https://myapp.com Access-Control-Request-Method: DELETE Access-Control-Request-Headers: Content-Type
サーバーはこれに対して、
Access-Control-Allow-Origin: https://myapp.com Access-Control-Allow-Methods: GET, POST, PUT, DELETE Access-Control-Allow-Headers: Content-Type
と返せば、本リクエストが実行されます。
🔄 プリフライトの目的: ブラウザが「このリクエストは安全に実行できますか?」と事前に確認すること
5. 歴史と標準化の経緯
CORSは、W3C(World Wide Web Consortium) によって標準化が進められ、2014年に勧告されました。
Ajax革命の時代
背景には、Ajax(非同期通信)の普及があります。2000年代半ば、Google MapsやGmailなどが登場し、ブラウザからAPIを叩くことが急速に増えました。
しかし「同一オリジンポリシー」があるため、当初は外部APIと連携するのが難しく、開発者は次のような工夫をしていました:
当時の迂回策
JSONP(JSON with Padding)
リバースプロキシ
CORSの誕生
こうした迂回策の不便さを解消するために、CORSが導入されたのです。
📅 歴史的意義: CORSにより、Webアプリケーションの可能性が大幅に広がりました。
6. よくある開発現場でのつまずき
ケース1:ローカル環境でのテスト
問題: http://localhost:3000
→ http://api.localhost:5000
この場合も別オリジン扱いとなり、CORSエラーが出ます。
解決策:
Access-Control-Allow-Origin: *
を一時的に許可next.config.js
でプロキシ設定// next.config.js module.exports = { async rewrites() { return [ { source: '/api/:path*', destination: 'http://localhost:5000/api/:path*' } ] } }
ケース2:本番環境での設定漏れ
問題: APIサーバーにCORSヘッダーが設定されていないと、フロントからは必ずエラーになります。
確認すべき箇所:
nginx.conf
の設定django-cors-headers
の設定ケース3:認証付きAPIでの問題
問題: CookieやAuthorizationヘッダーを使う場合、追加設定が必要
必要な設定:
Access-Control-Allow-Credentials: true Access-Control-Allow-Origin: https://myapp.com // *は使えない
⚠️ 注意:Access-Control-Allow-Credentials: true
の場合、Access-Control-Allow-Origin
に*
は使用できません。
7. CORSのメリット・デメリット
メリット
セキュリティの向上
開発の柔軟性
デメリット
設定の複雑さ
性能への影響
⚖️ バランス: セキュリティと利便性のバランスを取る仕組みとして設計されています。
8. 最新の状況とブラウザ対応
ブラウザサポート状況
2025年現在、主要ブラウザ(Chrome, Firefox, Safari, Edge)はすべてCORSを実装しています。
一部仕様解釈に差はありますが、基本的な挙動は共通化されており、開発者は安心して使えます。
セキュリティ強化の流れ
特にセキュリティ強化の流れとして:
SameSite Cookie属性との併用
Set-Cookie: sessionId=abc123; SameSite=Strict; Secure
CORSとCSRFトークンの組み合わせ
今後の展望
🔮 将来性: CORSは今後もWebセキュリティの基盤として重要な役割を果たし続けます。
9. API設計での注意点
みなさんがAPIを設計・開発する際には、以下に注意してください:
セキュリティの原則
1. 許可するオリジンを最小限に
// ❌ 危険 Access-Control-Allow-Origin: * // ✅ 安全 Access-Control-Allow-Origin: https://myapp.com
2. 必要なHTTPメソッドとヘッダーだけを許可
// ❌ 過度に広い許可 Access-Control-Allow-Methods: * // ✅ 必要最小限 Access-Control-Allow-Methods: GET, POST
3. 認証が絡む場合は特に注意
Access-Control-Allow-Credentials: true Access-Control-Allow-Origin: https://myapp.com // *は使えない
実装時のチェックリスト
*
を使用していないcredentials: true
を設定🛡️ セキュリティファースト: 便利さよりも安全性を優先することが重要です。
まとめ
CORSとは何かを一言でまとめると、
「ブラウザがユーザーを守るために設けた"通信のルール"を、サーバーが許可する仕組み」 です。
この記事で学んだこと
実践的な理解
これらを理解しておけば、CORSエラーに出会っても「なるほど、サーバー側がこう返していないからだな」と冷静に判断できるでしょう。
重要なポイント
ネイティブアプリやサーバーサイドではCORSは基本的に関係ありません。これはあくまで「ブラウザの仕様」 だからです。
みなさんも次にCORSエラーを見かけたら、「ブラウザが安全確認をしてくれているんだ」と思い出してください。
最後に
CORSは複雑に見えますが、その背景には「ユーザーの安全を守る」という重要な目的があります。
適切に理解し、実装することで、安全で使いやすいWebアプリケーションを作ることができるのです。
💡 覚えておいてください: CORSエラーは「問題」ではなく、「ブラウザが正常に働いている証拠」です。