ALBの「Verify JWT」機能をLaravelアプリで採用した場合の調査結果

technologies

はじめに

ベンジャミンのクワバラです。2025/11/12にAWS Application Load Balancer (ALB) にて、リクエストのJWT(JSON Web Token)を検証する機能(Verify JWT)が追加されました。

https://aws.amazon.com/jp/about-aws/whats-new/2025/11/application-load-balancer-jwt-verification

これまでアプリケーションコード(Laravelなど)内で行っていた「認証トークンの検証処理」を、ロードバランサー側に任せることができるこの機能。弊社ではフロントエンドはAmplify、バックエンドはLaravel APIを組み合わせるアーキテクチャを採用することがあるため、この機能を利用できないか調査してみました。

ALBの「Verify JWT」機能とは

AWS Application Load Balancer (ALB) のリスナールールにおいて、リクエストに含まれる JWT (JSON Web Token) の署名や有効期限を、ALB側で検証する機能です。これにより、不正なリクエストをALB側で即座に遮断でき、ALBのバックエンド (アプリケーションサーバー) の CPU負荷軽減とBOTからの防御を同時に実現することができます。

  1. CPU負荷低減: 署名検証という重い計算処理(RSA/ECDSA等)をLaravelアプリケーションから排除することができます。
  2. BOTからの防御: 不正なトークンやBotなどのリクエストはALBでブロックされるため、Laravelが起動することすらありません。サーバーリソースを「本来のビジネスロジック」だけに集中させることができます。

アーキテクチャパターン

この機能は、フロントエンドとバックエンドが分離している構成で利用するのが良さそうです。(フロントエンドとバックエンドを全てLaravelで担うモノリス構成では構成が複雑になり、おすすめしないです。)

  • フロントエンド: AWS Amplify / React / Vue.js など
  • バックエンド: AWS Fargate / EC2 (Laravel API)

処理フロー

  1. ログイン: ユーザーはAmplify側でCognito等を使ってログインし、JWTを取得します。
  2. リクエスト: AmplifyからALBへ、ヘッダーに Authorization: Bearer <token> を付与してAPIリクエストを送ります。
  3. ALB検証: ALBが署名や有効期限を検証します。
    • NGの場合: ALBが即座に 401 Unauthorized を返します(Laravelには届きません)。
    • OKの場合: ヘッダーをそのまま維持してLaravelへ転送します。
  4. アプリ処理: Laravelはリクエストを受け取り、JSONを返します。

Laravel側での実装例

ALBですでに「署名の正当性」は保証されているため、Laravel側では重い署名検証をスキップし、ペイロード(中身)のデコードのみを行う「軽量なミドルウェア」を実装するのが最も効率的です。

ミドルウェアの実装例

app/Http/Middleware/TrustAlbJwt.php を作成し、以下のように実装します。

PHP

<?php

namespace App\Http\Middleware;

use Closure;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use App\Models\User;

class TrustAlbJwt
{
    public function handle(Request $request, Closure $next)
    {
        $token = $request->bearerToken();

        // ALBを通過している前提のため、署名検証はスキップしデコードのみ実施
        // 注意: 必ずセキュリティグループ等でALB経由以外のアクセスを遮断すること
        $parts = explode('.', $token);
        if (count($parts) !== 3) {
            return response()->json(['message' => 'Invalid Token'], 401);
        }

        $payload = json_decode(base64_decode(str_replace(['-', '_'], ['+', '/'], $parts[1])), true);
        $userId = $payload['sub'] ?? null;

        if ($userId) {
            // ステートレス認証としてユーザーをセット
            // 毎回DBを引くか、IDのみで処理するかは要件次第
            $user = User::find($userId);
            if ($user) {
                Auth::setUser($user);
            }
        }

        return $next($request);
    }
}

重要なセキュリティ設定

この実装を行う場合、「ALBを経由しない直接アクセス」を絶対に防ぐ必要があります。

EC2やFargateのセキュリティグループ設定で、インバウンドルールを「ALBのセキュリティグループからのHTTP許可のみ」に絞り、インターネットからの直接アクセスを遮断してください。

導入時の注意点:CORS設定

Amplify(フロントエンド)とALB(API)のドメインが異なる場合、CORS(Cross-Origin Resource Sharing)の設定が必須です。

Laravelの config/cors.php にて、Amplifyのドメインを許可設定に追加してください。また、ALBが401エラーを返す際にCORSヘッダーが不足してブラウザ側でネットワークエラーに見える場合があるため、開発中はALBの設定を慎重に行う必要があります。

コストへの影響

今回の「Verify JWT」機能を利用することでAWS利用料がどのくらい増えるのかと懸念されるかもしれませんが、トータルコストは下がると推測しています。

  • ALB費用: ALBに処理をさせることでLCU(従量課金)がわずかに発生することが想定されますが、以下と比べると誤差の範囲内だと考えています。
  • サーバー費用: 不正なリクエストをALBが代わりに処理してくれることでサーバーの負荷が下がり、台数やスペックを下げる検討ができるため、こちらの削減効果の方が大きくなります。

まとめ

ALBの最新機能「Verify JWT」を活用することで、Laravelアプリケーションの負荷が下がることが見込め、より効率的で堅牢なAPIサーバーにすることができそうです。

弊社でも新規でバックエンドLaravelを採用するアプリケーション開発があれば試してみようと思います。

Related posts