ClaudeNext.jsOct 23, 2023, 2:00 PM

How to Think About Security in Next.js

A condensed section focused on the key takeaways first.

Original Post

Quick Digest

Summary

A condensed section focused on the key takeaways first.

claudeenmodel: claude-sonnet-4-20250514

Next.js Security Best Practices for React Server Components

Key Points

  • Three data handling models with specific security trade-offs for different project types
  • Built-in protections including server-only imports and experimental taint APIs
  • Focus on preventing accidental data exposure through proper component design

Summary

This guide outlines security considerations for Next.js applications using React Server Components (RSC) in App Router, focusing on preventing accidental data exposure and establishing secure data handling patterns.

Key Points

Data Handling Models

  • HTTP APIs: Recommended for existing large projects - treat Server Components as untrusted, use fetch() for API calls with Zero Trust approach
  • Data Access Layer: Recommended for new projects - consolidate all data access in a separate JavaScript layer with consistent authorization checks
  • Component Level Data Access: Only for prototyping - requires careful auditing of "use client" files and prop interfaces

Security Protections

  • Use import 'server-only' to prevent server code from being imported by Client Components
  • Leverage class-based objects to prevent accidental serialization to client
  • Implement experimental React Taint APIs (experimental_taintObjectReference, experimental_taintUniqueValue) to mark sensitive data
  • Environment variables are server-only by default unless prefixed with NEXT_PUBLIC_

Best Practices

  • Always use parameterized queries to prevent SQL injection
  • Apply principle of least privilege - Client Components should only receive minimal necessary data
  • Use Data Transfer Objects (DTOs) that are safe for client consumption
  • Maintain clear separation between Server Components and Client Components security policies

Full Translation

Translations

A translation section that keeps the flow of the original article.

claudejamodel: claude-sonnet-4-20250514

Next.jsにおけるセキュリティの考え方

Next.jsにおけるセキュリティの考え方

2023年10月23日(月)投稿者:Sebastian Markbåge @ sebmarkbage

App RouterのReact Server Components(RSC)は、従来の手法に関連する冗長性と潜在的なリスクの多くを排除する新しいパラダイムです。この新しさゆえに、開発者とセキュリティチームは、既存のセキュリティプロトコルをこのモデルに合わせることが困難な場合があります。この文書は、注意すべき領域、組み込まれた保護機能を強調し、アプリケーションの監査ガイドを含むことを目的としています。特に偶発的なデータ露出のリスクに焦点を当てています。

データ処理モデルの選択

React Server Componentsはサーバーとクライアントの境界を曖昧にします。データ処理は、情報がどこで処理され、その後利用可能になるかを理解する上で最も重要です。最初に行う必要があるのは、プロジェクトに適したデータ処理アプローチを選択することです。

  • HTTP APIs(既存の大規模プロジェクト/組織に推奨)
  • Data Access Layer(新規プロジェクトに推奨)
  • Component Level Data Access(プロトタイピングと学習に推奨)

1つのアプローチに固執し、あまり混在させないことをお勧めします。これにより、コードベースで作業する開発者とセキュリティ監査者の両方にとって、何を期待すべきかが明確になります。例外は疑わしいものとして目立ちます。

HTTP APIs

既存のプロジェクトでServer Componentsを採用する場合、推奨されるアプローチは、Server Componentsを実行時にSSRやクライアント内と同様に、デフォルトで安全でない/信頼できないものとして扱うことです。内部ネットワークや信頼ゾーンの仮定はなく、エンジニアはZero Trustの概念を適用できます。

代わりに、Server Componentsからクライアントで実行されるかのように、fetch()を使用してRESTやGraphQLなどのカスタムAPIエンドポイントのみを呼び出します。すべてのCookieを渡します。

データベースに接続する既存のgetStaticProps/getServerSidePropsがある場合、モデルを統合し、これらをAPIエンドポイントに移動して、1つの方法で物事を行うことをお勧めします。内部ネットワークからのフェッチが安全であると仮定するアクセス制御に注意してください。

このアプローチにより、セキュリティに特化した既存のバックエンドチームが既存のセキュリティプラクティスを適用できる既存の組織構造を維持できます。これらのチームがJavaScript以外の言語を使用している場合、このアプローチでうまく機能します。

Data Access Layer

新規プロジェクトに推奨されるアプローチは、JavaScriptコードベース内に別個のData Access Layerを作成し、すべてのデータアクセスをそこに統合することです。このアプローチにより、一貫したデータアクセスが保証され、認可バグが発生する可能性が減少します。単一のライブラリに統合するため、保守も容易になります。

現在のユーザーを受け入れ、データを返す前にユーザーがこのデータを見ることができるかどうかをチェックする内部JavaScriptライブラリを構築します。原則として、Server Component関数本体は、リクエストを発行している現在のユーザーがアクセスを許可されているデータのみを見るべきです。

// data/auth.tsx
import { cache } from 'react';
import { cookies } from 'next/headers';

export const getCurrentUser = cache(async () => {
  const token = cookies().get('AUTH_TOKEN');
  const decodedToken = await decryptAndValidate(token);
  return new User(decodedToken.id);
});
// data/user-dto.tsx
import 'server-only';
import { getCurrentUser } from './auth';

export async function getProfileDTO(slug: string) {
  const [rows] = await sql`SELECT * FROM user WHERE slug = ${slug}`;
  const userData = rows[0];
  const currentUser = await getCurrentUser();
  
  return {
    username: canSeeUsername(currentUser) ? userData.username : null,
    phonenumber: canSeePhoneNumber(currentUser, userData.team) ? userData.phonenumber : null,
  };
}

これらのメソッドは、そのままクライアントに転送しても安全なオブジェクトを公開する必要があります。これらをData Transfer Objects(DTO)と呼び、クライアントが消費する準備ができていることを明確にします。

Component Level Data Access

別のアプローチは、データベースクエリを直接Server Componentsに配置することです。このアプローチは、迅速な反復とプロトタイピングにのみ適しています。

このアプローチでは、「use client」ファイルを慎重に監査する必要があります。監査とPRレビューの際は、すべてのエクスポートされた関数と、型シグネチャがUserのような過度に広範なオブジェクトを受け入れるか、tokencreditCardのようなプロパティを含むかどうかを確認してください。

Server Only

サーバーでのみ実行されるべきコードは、次のようにマークできます:

import 'server-only';

これにより、Client Componentがこのモジュールをインポートしようとするとビルドエラーが発生します。

Next.js 14の実験的機能

次期Next.js 14リリースでは、next.config.jsでtaintフラグを有効にすることで、実験的なReact Taint APIを試すことができます:

// next.config.js
module.exports = {
  experimental: {
    taint: true,
  },
};
// app/data.ts
import { experimental_taintObjectReference } from 'react';

export async function getUserData(id) {
  const data = ...;
  experimental_taintObjectReference('Do not pass user data to the client', data);
  return data;
}

トークンなどの一意の文字列の場合、taintUniqueValueを使用して生の値もブロックできます。

環境変数

デフォルトでは、環境変数はサーバーでのみ利用可能です。慣例により、Next.jsはNEXT_PUBLIC_で始まる環境変数もクライアントに公開します。これにより、クライアントで利用可能であるべき特定の明示的な設定を公開できます。

SSR vs RSC

初期ロードでは、Next.jsはHTMLを生成するためにServer ComponentsとClient Componentsの両方をサーバーで実行します。Server Components(RSC)は、2つのモジュール間で情報が誤って露出することを避けるため、Client Componentsとは別のモジュールシステムで実行されます。

Server-side Rendering(SSR)を通じてレンダリングされるClient Componentsは、ブラウザクライアントと同じセキュリティポリシーとして考慮されるべきです。特権データやプライベートAPIにアクセスすべきではありません。