Back

CORSを理解する:リクエストが失敗する理由

CORSを理解する:リクエストが失敗する理由

JavaScriptアプリケーションがCORSエラーをスローする場合、それはコードの不具合ではありません。ブラウザが潜在的なセキュリティ脅威からユーザーを保護しているのです。これらのエラーが発生する理由を理解するには、ブラウザがクロスオリジンリクエストを処理する際の基本的なセキュリティモデルを把握する必要があります。

重要なポイント

  • CORSエラーは、適切なサーバー権限を持たないクロスオリジンリクエストをブラウザがブロックしたときに発生します
  • 同一オリジンポリシーは、異なるオリジン間のリクエストを制限することでユーザーを保護します
  • 単純なリクエストは直接進行しますが、複雑なリクエストはプリフライトOPTIONSチェックが必要です
  • CORSのデバッグには、ブラウザのネットワークタブの確認とサーバーレスポンスヘッダーの検証が必要です

同一オリジンポリシーの基礎

ブラウザは、主要なセキュリティメカニズムとして同一オリジンポリシーを適用します。オリジンは3つの部分で構成されます:プロトコル(https://)、ドメイン(example.com)、ポート(:3000)。これらが完全に一致する場合、リクエストは自由に流れます。わずかでも異なる場合、クロスオリジンリクエストを行っていることになります。

以下のオリジンを考えてみましょう:

  • https://app.example.comhttps://api.example.com (異なるサブドメイン = 異なるオリジン)
  • http://localhost:3000http://localhost:3001 (異なるポート = 異なるオリジン)
  • http://example.comhttps://example.com (異なるプロトコル = 異なるオリジン)

このポリシーがなければ、どのウェブサイトもあなたのGmailを読み取ったり、銀行データにアクセスしたり、あなたの代わりにリクエストを行ったりできてしまいます。Cross-Origin Resource Sharing(CORS)は、これらの制限を制御された形で緩和する仕組みを提供します。

ブラウザによるCORSの適用方法

ブラウザが執行者であり、サーバーではありません。この区別は重要です。なぜなら、一般的な誤解を説明できるからです:

  1. 「Postman/curlでは動作する」 - これらのツールはブラウザではないため、CORSを適用しません
  2. no-corsモードを追加すれば修正できる」 - これはCORSを無効化せず、読み取れない不透明なレスポンスを作成します
  3. 「サーバーがリクエストをブロックしている」 - サーバーは正常に応答しますが、ブラウザがレスポンスへのアクセスをブロックします

クロスオリジンリクエストを行うと、ブラウザは自動的にOriginヘッダーを追加します。サーバーは、あなたのオリジンと一致するAccess-Control-Allow-Originヘッダー(または公開リソースの場合は*)で応答する必要があります。一致するヘッダーがない場合、ブラウザはレスポンスへのアクセスをブロックします。これがCORSエラーの原因です。

単純なリクエストとプリフライトリクエスト

すべてのリクエストが同じCORS動作を引き起こすわけではありません。単純なリクエストは即座に通過しますが、その他のリクエストはプリフライトリクエストが必要です。

単純なリクエスト(プリフライトなし)

これらのリクエストは以下のすべての条件を満たします:

  • メソッド:GETHEAD、またはPOST
  • ヘッダー:単純なヘッダーのみ(AcceptContent-LanguageContent-Type)
  • Content-Type:application/x-www-form-urlencodedmultipart/form-data、またはtext/plainのみ

プリフライトをトリガーするリクエスト

単純な条件を満たさないリクエストは、OPTIONSプリフライトをトリガーします:

  • PUTDELETEPATCHなどのメソッド
  • カスタムヘッダー(AuthorizationX-API-Key)
  • Content-Type: application/json(そうです、JSONはプリフライトをトリガーします)

プリフライトは、実際のリクエストを送信する前に許可を求めます。サーバーは適切なヘッダーで応答する必要があります:

  • Access-Control-Allow-Methods(許可されるメソッド)
  • Access-Control-Allow-Headers(許可されるヘッダー)
  • Access-Control-Max-Age(この許可をキャッシュする期間)

CORSの一般的な失敗ポイント

ヘッダーの欠落または不正確

サーバーがAccess-Control-Allow-Originヘッダーを返さないか、あなたのオリジンと一致しません。覚えておいてください:http://localhost:3000http://localhost:3001は異なるオリジンです。

認証情報の制約

認証情報を含める(credentials: 'include'またはwithCredentials: true)と、制限が追加されます:

  • サーバーはAccess-Control-Allow-Credentials: trueを含める必要があります
  • Access-Control-Allow-Origin*にできません。正確なオリジンを指定する必要があります
  • CookieはSameSite要件を満たす必要があります

リダイレクトの複雑さ

CORSとリダイレクトは相性が悪いです。CORSリクエスト中に異なるオリジンへのリダイレクトが発生すると、ブラウザがオリジンの変更を正しく処理できないため、しばしば失敗します。CORSリクエストではクロスオリジンリダイレクトを避けてください。

プライベートネットワークアクセス

最新のブラウザは、公開ウェブサイトがプライベートネットワークリソース(localhost、192.168.x.x、10.x.x.x)にアクセスする際に追加の保護を加えます。これらのリクエストは、Access-Control-Allow-Private-Networkのような追加ヘッダーが必要になる場合があり、単純なリクエストでもプリフライトをトリガーする可能性があります。この保護により、外部ウェブサイトがローカルネットワークをスキャンすることを防ぎます。

効果的なCORSのデバッグ

CORSエラーに直面した場合:

  1. ブラウザのネットワークタブを確認 - プリフライトOPTIONSリクエストを探し、リクエストとレスポンスの両方のヘッダーを調査します
  2. 正確なエラーメッセージを確認 - 「CORSヘッダー’Access-Control-Allow-Origin’が欠落しています」と「CORSヘッダー’Access-Control-Allow-Origin’が一致しません」は、異なる問題を示しています
  3. 最初は認証情報なしでテスト - credentials: 'include'を削除して、認証情報関連の問題を分離します
  4. オリジンの一致を確認 - プロトコル、ドメイン、ポートがすべて完全に一致していることを確認します

まとめ

CORSエラーは恣意的な障害ではありません。悪意のあるクロスオリジンリクエストからユーザーを保護するブラウザの働きです。サーバーはCORSヘッダーを通じてどのオリジンがリソースにアクセスできるかを宣言し、ブラウザがこれらのルールを適用します。このモデルを理解することで、CORSは謎のブロッカーから、体系的にデバッグできる予測可能なシステムへと変わります。

リクエストが失敗した場合、それが単純なリクエストかプリフライトリクエストかを確認し、サーバーのCORSヘッダーがあなたのオリジンと完全に一致することを検証し、Postmanのようなツールはこれらのチェックを完全にバイパスすることを覚えておいてください。ブラウザは仕事をしているのです。あなたの仕事は、サーバーが正しい権限を提供していることを確認することです。

よくある質問

Postmanやその他のAPIテストツールはCORSポリシーを適用しません。ブラウザのみがこれらのセキュリティ制限を実装します。ブラウザリクエストを成功させるには、サーバーが適切なAccess-Control-Allow-Originヘッダーを送信する必要があります。

ブラウザはセキュリティ機能を無効化するフラグを提供していますが、これはリスクがあり、すべてのサイトに影響します。代わりに、開発サーバーを適切なCORSヘッダーを送信するように設定するか、開発中にクロスオリジンリクエストを処理するプロキシサーバーを使用してください。

CORS仕様では、3つのコンテンツタイプのみを単純と見なします:application/x-www-form-urlencoded、multipart/form-data、text/plain。application/jsonを含む他のコンテンツタイプは、権限を確認するためにプリフライトOPTIONSリクエストをトリガーします。

Understand every bug

Uncover frustrations, understand bugs and fix slowdowns like never before with OpenReplay — the open-source session replay tool for developers. Self-host it in minutes, and have complete control over your customer data. Check our GitHub repo and join the thousands of developers in our community.

OpenReplay