•6 min read

Next.js15のセキュリティアーキテクチャ: CSRF、SSRF、ステートインジェクションからServer Actionsを強化する

Next.js15のセキュリティアーキテクチャ: CSRF、SSRF、ステートインジェクションからServer Actionsを強化する

Next.js 15では、特にReact 19とServer Actionsの機能強化により、アーキテクチャが大きく変化しました。これらの機能はフルスタック開発を効率化する一方で、アプリケーションの攻撃対象領域も拡大させます。このガイドでは、Next.js 15のServer Actionsを、クロスサイトリクエストフォージェリ(CSRF)、サーバーサイドリクエストフォージェリ(SSRF)、ステートインジェクションといった一般的なウェブ脆弱性から保護するための堅牢なセキュリティアーキテクチャについて詳しく説明します。本稿では、本番環境レベルのパターンを用いた多層防御戦略の実装に焦点を当てます。

Audio Briefing
0:00 / 0:00

Next.js 15 Server Actionsの攻撃対象領域を理解する

Next.js 15のServer Actionsは、サーバー上で直接実行される非同期関数です。これらはクライアントコンポーネント、サーバーコンポーネント、またはHTMLフォームから直接呼び出すことができます。このパラダイムは、データミューテーションとサーバーサイドロジックを簡素化し、フォーム送信やクライアントサイドの関数呼び出しを、実質的に直接的なサーバーサイドAPI呼び出しに変換します。

主なセキュリティ上の影響は以下の点から生じます。

  1. 直接的なサーバー実行: Server Actionsは特権環境で実行されることが多く、データベース、内部サービス、機密性の高い環境変数へのアクセス権を持つ場合があります。
  2. クライアント起点の呼び出し: Server Actionsはサーバー上で実行されますが、その呼び出しはクライアントサイドのイベント(フォーム送信、startTransition呼び出し)によってトリガーされます。これにより、クライアントから発生する典型的なウェブ攻撃ベクトルにさらされます。
  3. 設計上ステートレス: Server Actionsは通常ステートレスで、単一のリクエストを処理します。しかし、ステートはクッキーを介して暗黙的に管理されたり、フォームデータを介して明示的に渡されたりするため、ステートインジェクションが懸念されます。
  4. 暗黙的なPOSTエンドポイント: 各Server Actionは実質的にPOSTエンドポイントを作成します。明示的な保護がない場合、これらのエンドポイントは認証されていない、または悪意のある呼び出しに対して脆弱です。

Server Actionsを保護するには、ネットワークレベルの制御、堅牢な入力検証、アプリケーションレベルのセキュリティヘッダーを組み合わせた多層的なアプローチが必要です。

Advertisement

クロスサイトリクエストフォージェリ(CSRF)保護

CSRF攻撃は、ウェブアプリケーションが認証済みユーザーのブラウザに対して持つ信頼を悪用します。悪意のあるサイトは、ユーザーのブラウザを騙して、ユーザーの明示的な同意なしに、認証済みリクエストをアプリケーションに送信させ、アクションを実行させることができます。

Next.js 15の組み込み保護とHost/Origin検証

Next.js 15のServer Actionsは、ブラウザからfetchを介して呼び出される場合、ブラウザレベルのセキュリティメカニズムから本質的に恩恵を受けます。特に、OriginとHostヘッダーが重要です。

  • Originヘッダー: クロスオリジンリクエスト(異なるオリジンへのフォーム送信を含む)とともに送信されます。リクエストのオリジンを示します。
  • Hostヘッダー: リクエストが送信されているサーバーのドメイン名を示します。

Server Actionsの場合、Next.jsはこれらのヘッダーを内部的に検証に使用します。しかし、middleware.tsでの明示的な検証は、追加の防御層を提供し、カスタムエラーハンドリングを可能にします。

アーキテクチャの説明: middleware.tsファイルは、ルートハンドラーまたはServer Actionによってリクエストが処理される前に実行されます。これは、Host/Origin検証のようなグローバルなセキュリティチェックを実行するのに理想的な場所です。Originヘッダー(存在する場合)とHostヘッダーを、期待されるアプリケーションドメインと比較することで、信頼できないソースから発信されたリクエストを拒否できます。

// middleware.ts
import { NextResponse, type NextRequest } from 'next/server';

const ALLOWED_HOSTS = process.env.NEXT_PUBLIC_ALLOWED_HOSTS
  ? process.env.NEXT_PUBLIC_ALLOWED_HOSTS.split(',')
  : ['locionic.com', 'www.locionic.com']; // Replace with your actual domains

export async function middleware(request: NextRequest) {
  const host = request.headers.get('host');
  const origin = request.headers.get('origin');
  const xInvokeAction = request.headers.get('x-invoke-action'); // Specific to Server Actions

  // 1. Host Header Validation
  if (host && !ALLOWED_HOSTS.includes(host)) {
    console.warn(`CSRF: Blocked request due to untrusted Host: ${host}`);
    return new NextResponse('Unauthorized Host', { status: 403 });
  }

  // 2. Origin Header Validation for Server Actions
  // Server Actions typically send an 'Origin' header, especially cross-origin.
  // For same-origin requests, 'Origin' might be null or same as 'Host'.
  // We specifically check 'x-invoke-action' to target Server Action requests.
  if (xInvokeAction) {
    if (origin && !ALLOWED_HOSTS.some(allowedHost => origin.endsWith(allowedHost))) {
      console.warn(`CSRF: Blocked Server Action due to untrusted Origin: ${origin}`);
      return new NextResponse('Unauthorized Origin for Server Action', { status: 403 });
    }
    // If origin is null/undefined for a Server Action, it's likely a same-origin form submission
    // or a non-browser client. Further checks might be needed for non-browser clients.
  }

  return NextResponse.next();
}

export const config = {
  matcher: [
    /*
     * Match all request paths except for the ones starting with:
     * - _next/static (static files)
     * - _next/image (image optimization files)
     * - favicon.ico (favicon file)
     * - api/auth (auth routes, if handled separately)
     * - Any public files in /public folder
     */
    '/((?!_next/static|_next/image|favicon.ico|api/auth|.*\\.(?:png|jpg|jpeg|gif|webp|svg|ico|js|css|map)$).*)',
  ],
};

トレードオフとレイテンシ:

| メソッド | 保護レベル | 複雑さ | レイテンシへの影響 | トレードオフ

Share this article:

Stay Updated

Get the latest posts delivered straight to your inbox.

Free Developer Utilities

Free In-Browser Developer Tools

Clean AI CLI logs, build cron expressions, decode JWTs, and calculate chmod permissions offline.

Explore Tools
Advertisement