Featured image of post CORS(オリジン間リソース共有)エラーのメカニズムと適切なサーバー応答 Featured image of post CORS(オリジン間リソース共有)エラーのメカニズムと適切なサーバー応答

CORS(オリジン間リソース共有)エラーのメカニズムと適切なサーバー応答

CORS(オリジン間リソース共有)エラーのメカニズムと適切なサーバー応答設定を徹底解剖。プリフライトリクエストの役割、Access-Control-Allow-OriginなどのHTTPヘッダーの正しい設定方法、フロントエンド開発で遭遇しがちなCORS問題の解決策を解説します。

はじめに

CORS(Cross-Origin Resource Sharing) は、ブラウザが異なるオリジン間のリソースアクセスを制御するセキュリティ機構です。https://app.example.com から https://api.example.org へのリクエストは、デフォルトで 同一オリジンポリシー によりブロックされます。CORS は HTTP ヘッダーを通じてこの制限を安全に緩和します。本記事では CORS の全体像、プリフライトリクエストの仕組み、そしてエラーの解決策を解説します。


同一オリジンポリシー

オリジンスキームホストポート の組み合わせで定義されます:

URLオリジン
https://example.com/page1https://example.com
https://example.com/page2同一オリジン
http://example.com/page1異なるオリジン(スキーム違い)
https://api.example.com異なるオリジン(ホスト違い)
https://example.com:3000異なるオリジン(ポート違い)

同一オリジンポリシーは悪意あるサイトが他サイトのデータを読み取ることを防ぎます。


シンプルリクエストとプリフライトリクエスト

CORS は シンプルリクエストプリフライト を要するリクエストに分類されます。

シンプルリクエスト の条件:

  • メソッド: GETHEADPOST
  • Content-Type: application/x-www-form-urlencodedmultipart/form-datatext/plain
  • カスタムヘッダーなし

シンプルリクエストは実際のリクエストを送信し、レスポンスの CORS ヘッダーを確認します。

それ以外のリクエストは プリフライト — 実際のリクエスト前に OPTIONS メソッドを送信します:

OPTIONS /api/data HTTP/1.1
Host: api.example.org
Origin: https://app.example.com
Access-Control-Request-Method: POST
Access-Control-Request-Headers: Content-Type, Authorization

サーバーは適切な CORS ヘッダーで応答する必要があります。


CORS の主要レスポンスヘッダー

ヘッダー役割
Access-Control-Allow-Origin許可するオリジンを指定
Access-Control-Allow-Methods許可する HTTP メソッドを指定
Access-Control-Allow-Headers許可するカスタムリクエストヘッダー
Access-Control-Allow-Credentialsクレデンシャル(Cookie)送信を許可
Access-Control-Max-Ageプリフライト結果のキャッシュ時間
Access-Control-Expose-Headersクライアントから参照可能なレスポンスヘッダー

プリフライト応答の例:

HTTP/1.1 204 No Content
Access-Control-Allow-Origin: https://app.example.com
Access-Control-Allow-Methods: GET, POST, PUT, DELETE
Access-Control-Allow-Headers: Content-Type, Authorization
Access-Control-Max-Age: 86400

ワイルドカードと特定オリジン

Access-Control-Allow-Origin: * は任意のオリジンを許可しますが制約があります:

  • Access-Control-Allow-Credentials: true と併用不可
  • 公開読み取り専用 API に限定すべき

クレデンシャル付きリクエストでは明示的なオリジン指定が必要です:

Access-Control-Allow-Origin: https://app.example.com
Access-Control-Allow-Credentials: true

複数オリジンを許可する場合、サーバー側でリクエスト元のオリジンを検証し動的にエコーバックします。


クロスオリジンで Cookie を送信するにはクライアントとサーバーの両方でオプトインが必要です:

クライアント(JavaScript):

fetch('https://api.example.org/data', {
  credentials: 'include',
});

サーバー(レスポンスヘッダー):

Access-Control-Allow-Origin: https://app.example.com
Access-Control-Allow-Credentials: true

credentials: 'include' がない限り、Cookie はクロスオリジンで送信されません。


よくある CORS エラーと解決策

エラーメッセージ原因解決策
No 'Access-Control-Allow-Origin' header presentCORS ヘッダー欠落Access-Control-Allow-Origin を追加
Origin mismatch許可リストにないオリジンホワイトリスト検証を実装
Credentials + wildcardワイルドカードとクレデンシャル* でなく特定オリジンを指定
Method not allowedメソッドが許可リストにないAllow-Methods に追加
Header not allowedカスタムヘッダー未許可Allow-Headers に追加

サーバー設定例

Express.js:

const cors = require('cors');
app.use(cors({
  origin: 'https://app.example.com',
  methods: ['GET', 'POST', 'PUT', 'DELETE'],
  credentials: true,
}));

Nginx:

add_header Access-Control-Allow-Origin "https://app.example.com";
add_header Access-Control-Allow-Methods "GET, POST, OPTIONS";
add_header Access-Control-Allow-Headers "Content-Type";

まとめ

CORS はユーザーを保護しつつ、正当なクロスオリジン通信を可能にする重要なセキュリティ層です。シンプルリクエストとプリフライトリクエストの違い、設定すべきヘッダー、クレデンシャルの適切な扱いを理解することで、CORS エラーに悩まされることなく安全なクロスオリジン通信を実現できます。サーバーサイドの CORS ポリシーを適切に構成し、セキュリティと利便性のバランスを取りましょう。