JWTの正しい理解とセキュアな実装ガイド

## 1. 前提知識：暗号化と署名の違い

### 暗号化（Encryption）の目的と仕組み

```mermaid
graph LR
    A[機密データ] --> B[暗号化キー]
    B --> C[暗号化されたデータ]
    C --> D[復号化キー]
    D --> E[元の機密データ]
    
    style A fill:#ffcccc
    style C fill:#ccffcc
    style E fill:#ffcccc
```

**暗号化の特徴：**
- データを第三者に読まれないよう**秘匿**することが目的
- 適切な復号化キーを持たない者はデータの内容を読めない
- データの**機密性**を保護

### デジタル署名（Digital Signature）の目的と仕組み

```mermaid
graph LR
    A[データ] --> B[ハッシュ化]
    B --> C[ハッシュ値]
    C --> D[秘密鍵で署名]
    D --> E[デジタル署名]
    
    F[データ + 署名] --> G[公開鍵で検証]
    G --> H{署名が正しい？}
    H -->|Yes| I[データは改ざんされていない]
    H -->|No| J[データが改ざんされている]
    
    style A fill:#ccccff
    style F fill:#ccccff
    style I fill:#ccffcc
    style J fill:#ffcccc
```

**デジタル署名の特徴：**
- データの**完全性**（改ざんされていないこと）を保証
- **認証**（誰が作成したかの証明）を提供
- データ自体は暗号化されず、誰でも読める

## 2. JWTの構造と動作原理

### JWTの構造

```mermaid
graph TB
    JWT[JWT Token] --> Header[Header<br/>ヘッダー]
    JWT --> Payload[Payload<br/>ペイロード]
    JWT --> Signature[Signature<br/>署名]
    
    Header --> H1[アルゴリズム情報]
    Header --> H2[トークンタイプ]
    
    Payload --> P1[ユーザーID]
    Payload --> P2[権限情報]
    Payload --> P3[有効期限]
    
    Signature --> S1[Header + Payload]
    S1 --> S2[秘密鍵で署名]
    
    style Header fill:#e1f5fe
    style Payload fill:#fff3e0
    style Signature fill:#e8f5e8
```

### JWTの実際の形式

```
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c
```

**各部分の説明：**
- **Header（赤色部分）**: Base64エンコードされたヘッダー情報
- **Payload（青色部分）**: Base64エンコードされたペイロード（**暗号化されていない**）
- **Signature（緑色部分）**: Header + Payloadの署名

### 重要なポイント：ペイロードは暗号化されていない

```mermaid
graph LR
    A[JWT Payload] --> B[Base64 Decode]
    B --> C[Plain Text JSON]
    
    C --> D["{\n  'sub': '1234567890',\n  'name': 'John Doe',\n  'admin': true\n}"]
    
    style A fill:#fff3e0
    style C fill:#ffcccc
    style D fill:#ffcccc
```

## 3. 現在の実装における問題点

### 間違った使用例：機密データをJWTに含める

```mermaid
sequenceDiagram
    participant C as Client
    participant S as Server
    participant DB as Database
    
    C->>S: ログイン要求
    S->>DB: ユーザー認証
    DB-->>S: ユーザー情報（機密データを含む）
    
    Note over S: ❌ 機密データをJWTに含める
    S->>S: JWT生成（機密データ含む）
    S-->>C: JWT（機密データが丸見え）
    
    Note over C: ❌ 機密データがBase64デコードで読める
    C->>C: JWT解析（機密データ取得）
```

**問題点：**
- 機密情報がBase64エンコードされただけでクライアントに送信
- 悪意のある第三者が容易に内容を読み取り可能
- JWTの設計思想と異なる用途での使用

### セキュリティリスクの可視化

```mermaid
graph TD
    A[JWT with Secret Data] --> B[Base64 Decode]
    B --> C[機密情報が露出]
    
    C --> D[個人情報漏洩]
    C --> E[API キー漏洩]
    C --> F[内部情報漏洩]
    
    style A fill:#ffcccc
    style B fill:#ffcccc
    style C fill:#ff9999
    style D fill:#ff6666
    style E fill:#ff6666
    style F fill:#ff6666
```

## 4. 正しいJWTの使用方法

### 認証トークンとしての適切な使用

```mermaid
sequenceDiagram
    participant C as Client
    participant S as Server
    participant DB as Database
    
    C->>S: ログイン要求
    S->>DB: ユーザー認証
    DB-->>S: 認証成功
    
    Note over S: ✅ 公開しても問題ない情報のみ含める
    S->>S: JWT生成（ユーザーID, 権限, 有効期限）
    S-->>C: JWT（安全な情報のみ）
    
    C->>S: API要求 + JWT
    S->>S: JWT検証（署名確認）
    
    alt JWT有効
        S->>DB: 必要に応じて追加データ取得
        DB-->>S: 機密データ
        S-->>C: レスポンス
    else JWT無効
        S-->>C: 認証エラー
    end
```

### JWTに含めるべき情報 vs 含めるべきでない情報

```mermaid
graph TB
    subgraph "✅ JWTに含めても良い情報"
        A1[ユーザーID]
        A2[権限レベル]
        A3[有効期限]
        A4[発行者情報]
        A5[トークンID]
    end
    
    subgraph "❌ JWTに含めるべきでない情報"
        B1[パスワード]
        B2[個人情報]
        B3[APIキー]
        B4[クレジットカード情報]
        B5[内部システム情報]
    end
    
    style A1 fill:#ccffcc
    style A2 fill:#ccffcc
    style A3 fill:#ccffcc
    style A4 fill:#ccffcc
    style A5 fill:#ccffcc
    
    style B1 fill:#ffcccc
    style B2 fill:#ffcccc
    style B3 fill:#ffcccc
    style B4 fill:#ffcccc
    style B5 fill:#ffcccc
```

## 5. 機密データの適切な取り扱い方法

### アーキテクチャパターンの比較

#### 現在の問題のあるパターン

```mermaid
graph LR
    A[Server] --> B[JWT with Secret Data]
    B --> C[Client]
    
    style B fill:#ffcccc
    
    Note1[機密データが<br/>クライアントに露出]
```

#### 推奨パターン1：サーバーサイド管理

```mermaid
graph TB
    A[Client] --> B[JWT（ユーザーIDのみ）]
    B --> C[Server]
    C --> D[Session Store / Database]
    D --> E[機密データ取得]
    E --> C
    C --> A
    
    style B fill:#ccffcc
    style D fill:#e8f5e8
```

#### 推奨パターン2：適切な暗号化

```mermaid
graph LR
    A[Server] --> B[暗号化ライブラリ<br/>AES/RSA]
    B --> C[暗号化されたデータ]
    C --> D[Client]
    D --> E[必要時に復号化要求]
    E --> A
    
    style B fill:#ccffcc
    style C fill:#ccffcc
```

### Ruby on Railsでの実装例

#### 現在の問題のあるコード例

```ruby
# ❌ 問題のある実装
class AuthenticationController < ApplicationController
  def login
    user = User.find_by(email: params[:email])
    if user&.authenticate(params[:password])
      # 機密情報もJWTに含めている
      payload = {
        user_id: user.id,
        email: user.email,
        credit_card_number: user.credit_card_number, # ❌ 機密情報
        api_key: user.api_key,                       # ❌ 機密情報
        internal_notes: user.internal_notes          # ❌ 機密情報
      }
      
      token = JWT.encode(payload, Rails.application.secret_key_base)
      render json: { token: token }
    end
  end
end
```

#### 推奨される実装

```ruby
# ✅ 推奨される実装
class AuthenticationController < ApplicationController
  def login
    user = User.find_by(email: params[:email])
    if user&.authenticate(params[:password])
      # 公開しても問題ない情報のみJWTに含める
      payload = {
        user_id: user.id,
        role: user.role,
        exp: 24.hours.from_now.to_i,
        iat: Time.now.to_i
      }
      
      token = JWT.encode(payload, Rails.application.secret_key_base)
      
      # 機密情報はサーバーサイドで管理
      user.update(last_login_at: Time.current)
      
      render json: { 
        token: token,
        user: {
          id: user.id,
          name: user.name,
          role: user.role
        }
      }
    end
  end
end

# 機密データが必要な場合は別途APIで取得
class UserDataController < ApplicationController
  before_action :authenticate_user!
  
  def show
    # JWTから取得したuser_idを使用して機密データを取得
    user_data = current_user.secure_data
    
    # 必要に応じて暗号化して送信
    encrypted_data = encrypt_sensitive_data(user_data)
    
    render json: { data: encrypted_data }
  end
  
  private
  
  def encrypt_sensitive_data(data)
    # AESなどの適切な暗号化ライブラリを使用
    cipher = OpenSSL::Cipher.new('AES-256-CBC')
    cipher.encrypt
    cipher.key = Rails.application.credentials.encryption_key
    cipher.iv = iv = cipher.random_iv
    
    encrypted = cipher.update(data.to_json) + cipher.final
    Base64.encode64(encrypted)
  end
end
```

## 7. まとめ

### 重要なポイント

```mermaid
graph TB
    A[JWT Security] --> B[JWTの本質]
    A --> C[適切な使用方法]
    A --> D[機密データの扱い]
    A --> E[移行のポイント]
    
    B --> B1[デジタル署名ライブラリ]
    B --> B2[暗号化ライブラリではない]
    B --> B3[完全性保証が目的]
    
    C --> C1[認証トークンとして]
    C --> C2[公開可能データのみ含める]
    C --> C3[ステートレス認証の実現]
    
    D --> D1[サーバーサイド管理]
    D --> D2[適切な暗号化ライブラリ使用]
    D --> D3[HTTPS通信の徹底]
    
    E --> E1[段階的な実装]
    E --> E2[十分なテスト]
    E --> E3[チーム全体での理解共有]
    
    style A fill:#e1f5fe
    style B fill:#fff3e0
    style C fill:#e8f5e8
    style D fill:#fce4ec
    style E fill:#f3e5f5
```

**結論：** JWTは認証のためのツールであり、暗号化のためのツールではありません。機密データの保護には適切な暗号化ライブラリと設計パターンを使用し、JWTは本来の目的である認証と完全性保証に使用することが重要です。