Laravel 11でのCORS設定: 環境分離とセキュリティを考慮した実装方法

こんにちは、いわむらです。

はじめに

Laravel 11がリリースされ、CORS設定の方法に変更がありました。過去のバージョンではconfig/cors.phpファイルがデフォルトで存在していましたが、Laravel 11では手動で作成する必要があります。

本記事では、Laravel 11における適切なCORS設定方法と、本番環境でも安全に運用できる環境分離の方法について解説します。

Laravel 11でのCORS設定の変更点

Laravel 11では、CORS設定ファイル(config/cors.php)がデフォルトで含まれなくなりました。過去のバージョンでは、新しいLaravelプロジェクトを作成すると、CORS設定ファイルが最初から存在していました。

設定ファイルの作成

Laravel 11でCORS設定が必要な場合は、以下のコマンドで設定ファイルを作成する必要があります:

php artisan config:publish cors

この変更により、CORSが不要なプロジェクトでは余計なファイルが生成されず、必要な場合のみ明示的に設定を追加することになります。

Laravel 11での正しいCORS設定

ステップ1: CORS設定ファイルの作成

Laravel 11では、以下のコマンドでCORS設定ファイルを作成できます:

php artisan config:publish cors

このコマンドにより、config/cors.php ファイルが作成されます。

ステップ2: 環境変数ベースの設定

作成された設定ファイルを環境変数ベースに変更します:

<?php
// config/cors.php

return [
    'paths' => ['api/*', 'sanctum/csrf-cookie'],

    'allowed_methods' => ['*'],

    // ❌ 危険な設定
    // 'allowed_origins' => ['*'],
    
    // ✅ 環境変数ベースの安全な設定
    'allowed_origins' => [
        env('FRONTEND_URL', 'http://localhost:3000'),
    ],

    'allowed_origins_patterns' => [],

    'allowed_headers' => ['*'],

    'exposed_headers' => [],

    'max_age' => 0,

    // ✅ 環境に応じて制御
    'supports_credentials' => env('CORS_SUPPORTS_CREDENTIALS', false),
];

ステップ3: 環境変数の設定

.env ファイルに適切な環境変数を追加:

# CORS Configuration
FRONTEND_URL=http://localhost:3000
CORS_SUPPORTS_CREDENTIALS=false

ステップ4: ミドルウェアの設定確認

Laravel 11では bootstrap/app.php でミドルウェアが管理されています。CORSミドルウェアは自動的に適用されますが、必要に応じて追加設定も可能です:

<?php
// bootstrap/app.php

use Illuminate\Foundation\Application;
use Illuminate\Foundation\Configuration\Exceptions;
use Illuminate\Foundation\Configuration\Middleware;

return Application::configure(basePath: dirname(__DIR__))
    ->withRouting(
        web: __DIR__.'/../routes/web.php',
        api: __DIR__.'/../routes/api.php',
        commands: __DIR__.'/../routes/console.php',
        health: '/up',
    )
    ->withMiddleware(function (Middleware $middleware) {
        // Sanctumを使用している場合
        $middleware->api(prepend: [
            \Laravel\Sanctum\Http\Middleware\EnsureFrontendRequestsAreStateful::class,
        ]);
        
        // 必要に応じてCORSミドルウェアのエイリアス設定
        $middleware->alias([
            'cors' => \Illuminate\Http\Middleware\HandleCors::class,
        ]);
    })
    ->withExceptions(function (Exceptions $exceptions) {
        //
    })->create();

環境分離の方法

開発環境

# .env (開発環境)
FRONTEND_URL=http://localhost:3000
CORS_SUPPORTS_CREDENTIALS=false

ステージング環境

# .env (ステージング環境)
FRONTEND_URL=https://staging-app.example.com
CORS_SUPPORTS_CREDENTIALS=true

本番環境

# .env (本番環境)
FRONTEND_URL=https://app.example.com
CORS_SUPPORTS_CREDENTIALS=true

複数のフロントエンドドメインがある場合

管理画面など、複数のフロントエンドがある場合の設定例:

// config/cors.php
'allowed_origins' => [
    env('FRONTEND_URL'),
    env('ADMIN_FRONTEND_URL'),
    // 本番環境で複数のサブドメインを許可する場合
    'https://admin.example.com',
],
# .env
FRONTEND_URL=https://app.example.com
ADMIN_FRONTEND_URL=https://admin.example.com

セキュリティ上の重要な注意点

1. ワイルドカード設定の回避

// ❌ 本番環境では絶対に使用しない
'allowed_origins' => ['*'],

// ✅ 明示的にドメインを指定
'allowed_origins' => [
    env('FRONTEND_URL'),
    // 必要に応じて追加のドメイン
    'https://admin.example.com',
],

2. 認証情報の適切な管理

// 認証が必要なAPIの場合
'supports_credentials' => env('CORS_SUPPORTS_CREDENTIALS', true),

// 公開APIの場合
'supports_credentials' => false,

認証情報を含むリクエスト(Cookie、Authorization ヘッダーなど)を扱う場合は、supports_credentialstrue に設定し、allowed_origins にワイルドカード(*)は使用できません。

3. パスの限定

// 必要最小限のパスのみ許可
'paths' => [
    'api/*',           // APIルート
    'sanctum/csrf-cookie', // CSRF保護用(Sanctum使用時)
],

動作確認とトラブルシューティング

テスト用エンドポイントの作成

設定が正しく動作しているか確認するため、テスト用APIエンドポイントを作成します:

<?php
// routes/api.php

use Illuminate\Support\Facades\Route;

Route::get('/test-cors', function () {
    return response()->json([
        'message' => 'CORS is working!',
        'timestamp' => now(),
        'origin' => request()->header('Origin'),
    ]);
});

よくある問題と対処法

1. プリフライトリクエスト(OPTIONS)が失敗する

// フロントエンドでのテスト例
fetch('http://your-api.com/api/test-cors', {
    method: 'POST',
    headers: {
        'Content-Type': 'application/json',
        'Authorization': 'Bearer your-token'
    },
    body: JSON.stringify({ test: 'data' })
})

この場合、ブラウザは自動的にOPTIONSリクエストを送信します。allowed_methods['*'] または ['POST', 'OPTIONS'] が含まれていることを確認してください。

2. 認証情報付きリクエストが失敗する

// 認証情報を含むリクエスト
fetch('http://your-api.com/api/user', {
    method: 'GET',
    credentials: 'include', // これが重要
    headers: {
        'Authorization': 'Bearer your-token'
    }
})

この場合、supports_credentialstrue に設定されており、allowed_origins にワイルドカードが使用されていないことを確認してください。

デバッグ用の設定

開発中にCORSの動作を詳しく確認したい場合:

// config/cors.php (開発環境でのデバッグ用)
return [
    'paths' => ['api/*', 'sanctum/csrf-cookie'],
    'allowed_methods' => ['*'],
    'allowed_origins' => [
        env('FRONTEND_URL', 'http://localhost:3000'),
    ],
    'allowed_origins_patterns' => [],
    'allowed_headers' => ['*'],
    'exposed_headers' => ['X-Debug-Info'], // デバッグ情報用
    'max_age' => 0, // キャッシュ無効(開発時)
    'supports_credentials' => env('CORS_SUPPORTS_CREDENTIALS', false),
];

まとめ

Laravel 11でのCORS設定は、フレームワーク標準の機能を使用することで以下のメリットを得られます:

保守性の向上

  • 設定ファイルの手動作成により、不要な設定を排除
  • 環境変数による柔軟な設定管理

セキュリティの強化

  • 明示的なドメイン指定によるセキュリティリスクの軽減
  • 環境ごとの適切な認証情報管理

運用の安全性

  • 環境分離による設定ミスの防止
  • 本番環境での意図しないアクセス許可の回避

特に本番環境では、ワイルドカードの使用を避け、必要最小限のドメインのみを許可することが重要です。開発段階から環境変数ベースの設定を心がけることで、安全で保守性の高いAPIを構築できます。

CORS設定は一度正しく設定すれば、基本的にメンテナンスの必要がない部分です。しかし、新しいフロントエンドドメインの追加や、認証方式の変更時には設定の見直しが必要になるため、この記事を参考に適切な設定を維持してください。

参考リンク