🔒

CORSの仕組み - クロスオリジンリクエストを理解する

13分 で読める | 2025.12.10

CORSとは

CORS(Cross-Origin Resource Sharing)は、異なるオリジン間でのリソース共有を安全に行うためのブラウザの仕組みです。セキュリティ上の理由から、ブラウザはデフォルトで異なるオリジンへのリクエストを制限しています。

オリジンとは: スキーム(http/https)、ホスト、ポートの組み合わせです。https://example.com:443https://api.example.com:443は異なるオリジンです。

同一オリジンポリシー

ブラウザは同一オリジンポリシー(SOP: Same-Origin Policy)により、異なるオリジンへのリクエストを制限します。

https://app.example.com から:

✓ https://app.example.com/api  (同一オリジン)
✗ https://api.example.com/v1   (異なるホスト)
✗ http://app.example.com/api   (異なるスキーム)
✗ https://app.example.com:8080 (異なるポート)

CORSの基本フロー

シンプルリクエスト

以下の条件を満たすリクエストはプリフライトなしで送信されます。

  • メソッド: GET, HEAD, POST
  • ヘッダー: Accept, Accept-Language, Content-Language, Content-Type(一部のみ)
  • Content-Type: application/x-www-form-urlencoded, multipart/form-data, text/plain
ブラウザ → サーバー:
GET /api/users
Origin: https://app.example.com

サーバー → ブラウザ:
HTTP/1.1 200 OK
Access-Control-Allow-Origin: https://app.example.com

プリフライトリクエスト

カスタムヘッダーやJSON送信など、条件を満たさないリクエストは事前確認が必要です。

1. プリフライト(事前確認)
ブラウザ → サーバー:
OPTIONS /api/users
Origin: https://app.example.com
Access-Control-Request-Method: POST
Access-Control-Request-Headers: Content-Type, Authorization

サーバー → ブラウザ:
HTTP/1.1 204 No Content
Access-Control-Allow-Origin: https://app.example.com
Access-Control-Allow-Methods: POST, GET, OPTIONS
Access-Control-Allow-Headers: Content-Type, Authorization
Access-Control-Max-Age: 86400

2. 実際のリクエスト
ブラウザ → サーバー:
POST /api/users
Origin: https://app.example.com
Content-Type: application/json
Authorization: Bearer token123

CORSヘッダー

レスポンスヘッダー

ヘッダー説明
Access-Control-Allow-Origin許可するオリジン
Access-Control-Allow-Methods許可するHTTPメソッド
Access-Control-Allow-Headers許可するリクエストヘッダー
Access-Control-Allow-CredentialsCookieの送信を許可
Access-Control-Expose-HeadersJSからアクセス可能なヘッダー
Access-Control-Max-Ageプリフライト結果のキャッシュ時間

設定例(Express.js)

const cors = require('cors');

// 特定のオリジンを許可
app.use(cors({
  origin: 'https://app.example.com',
  methods: ['GET', 'POST', 'PUT', 'DELETE'],
  allowedHeaders: ['Content-Type', 'Authorization'],
  credentials: true,
  maxAge: 86400
}));

// 複数のオリジンを許可
app.use(cors({
  origin: ['https://app.example.com', 'https://admin.example.com'],
}));

// 動的にオリジンを検証
app.use(cors({
  origin: (origin, callback) => {
    const allowedOrigins = ['https://app.example.com'];
    if (!origin || allowedOrigins.includes(origin)) {
      callback(null, true);
    } else {
      callback(new Error('Not allowed by CORS'));
    }
  }
}));

Credentialsモード

Cookieや認証情報を含むリクエストには特別な設定が必要です。

// クライアント側
fetch('https://api.example.com/data', {
  credentials: 'include'  // Cookieを含める
});

// サーバー側
// Access-Control-Allow-Origin: * は使用不可
// 具体的なオリジンを指定する必要がある
Access-Control-Allow-Origin: https://app.example.com
Access-Control-Allow-Credentials: true

よくあるエラーと解決策

エラー1: No ‘Access-Control-Allow-Origin’ header

原因: サーバーがCORSヘッダーを返していない

解決策:
- サーバー側でCORSを設定
- プロキシを経由してリクエスト

エラー2: Wildcard with credentials

原因: credentials: 'include' と
      Access-Control-Allow-Origin: * の組み合わせ

解決策:
- 具体的なオリジンを指定
  Access-Control-Allow-Origin: https://app.example.com

エラー3: Method not allowed

原因: プリフライトでメソッドが許可されていない

解決策:
- Access-Control-Allow-Methods に必要なメソッドを追加

エラー4: Header not allowed

原因: カスタムヘッダーが許可されていない

解決策:
- Access-Control-Allow-Headers にヘッダーを追加

開発時のCORS対策

プロキシを使用

// Vite の設定例
export default defineConfig({
  server: {
    proxy: {
      '/api': {
        target: 'https://api.example.com',
        changeOrigin: true,
        rewrite: (path) => path.replace(/^\/api/, '')
      }
    }
  }
});

ブラウザ拡張機能

開発時のみCORSを無効化する拡張機能がありますが、本番環境では使用しないでください。

セキュリティ上の注意点

ワイルドカードの危険性

✗ 危険: すべてのオリジンを許可
Access-Control-Allow-Origin: *

✓ 推奨: 許可するオリジンを明示
Access-Control-Allow-Origin: https://app.example.com

オリジンの検証

// ✗ 悪い例: リクエストのOriginをそのまま返す
res.setHeader('Access-Control-Allow-Origin', req.headers.origin);

// ✓ 良い例: ホワイトリストで検証
const allowedOrigins = ['https://app.example.com'];
if (allowedOrigins.includes(req.headers.origin)) {
  res.setHeader('Access-Control-Allow-Origin', req.headers.origin);
}

まとめ

CORSは、Webアプリケーションのセキュリティを維持しながら、異なるオリジン間でのリソース共有を可能にする重要な仕組みです。適切なヘッダー設定と、オリジンの検証を行うことで、安全なクロスオリジン通信を実現できます。

← 一覧に戻る