# 機能設計書 3-多要素認証（MFA）

## 概要

本ドキュメントは、Chatwootシステムにおける多要素認証（MFA）機能の設計を記載する。TOTP（Time-based One-Time Password）およびバックアップコードによる2段階認証を実現する。

### 本機能の処理概要

本機能は、ユーザーアカウントのセキュリティを強化するための多要素認証を提供し、パスワード認証に加えてTOTPまたはバックアップコードによる追加認証を要求する。

**業務上の目的・背景**：カスタマーサポートシステムでは、顧客の個人情報や企業データを扱うため、アカウント乗っ取りのリスクを最小化する必要がある。MFA機能により、パスワードが漏洩した場合でも不正アクセスを防止し、エンタープライズグレードのセキュリティ基準を満たす。

**機能の利用シーン**：
- セキュリティ意識の高いユーザーがMFAを有効化
- 管理者が組織全体にMFAを推奨/強制
- ログイン時のTOTPコード入力
- 認証アプリを紛失した場合のバックアップコード使用

**主要な処理内容**：
1. MFAの有効化（OTPシークレット生成、QRコード表示用URI生成）
2. TOTP検証と有効化の確定
3. バックアップコードの生成（10個）
4. ログイン時のTOTP/バックアップコード検証
5. MFAの無効化

**関連システム・外部連携**：
- Google Authenticator、Microsoft Authenticator等のTOTPアプリ
- QRコードスキャン用のotpauth://プロトコル

**権限による制御**：MFA設定は自身のアカウントに対してのみ可能。MFA無効化時はパスワード再確認が必要。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 90 | MFA設定画面 | 主画面 | 多要素認証の設定、有効化・無効化 |
| 1 | ログイン画面 | 参照画面 | MFA検証が必要な場合のTOTP認証処理 |

## 機能種別

認証処理 / セキュリティ強化

## 入力仕様

### 入力パラメータ

#### MFA有効化

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| なし | - | - | MFA有効化開始時はパラメータ不要 | - |

#### MFA検証（有効化確定）

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| otp_code | String | Yes | TOTPワンタイムパスワード | 6桁数字 |

#### MFA無効化

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| otp_code | String | Yes | TOTPワンタイムパスワード | 6桁数字 |
| password | String | Yes | 現在のパスワード | 認証情報との一致確認 |

#### バックアップコード再生成

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| otp_code | String | Yes | TOTPワンタイムパスワード | 6桁数字 |

### 入力データソース

- 画面入力（MFA設定画面）
- TOTPアプリ（ワンタイムパスワード生成）

## 出力仕様

### 出力データ

#### MFA有効化開始（show）

| 項目名 | 型 | 説明 |
|--------|-----|------|
| mfa_enabled | Boolean | MFA有効状態 |
| mfa_feature_available | Boolean | MFA機能の利用可否 |
| provisioning_uri | String | QRコード用otpauth://URI |
| backup_codes_generated | Boolean | バックアップコード生成済みか |

#### MFA検証成功（verify）

| 項目名 | 型 | 説明 |
|--------|-----|------|
| backup_codes | Array[String] | バックアップコード10個（初回のみ） |

### 出力先

- HTTPレスポンスボディ（JSON形式）
- データベース（usersテーブル - OTPシークレット、バックアップコード）

## 処理フロー

### 処理シーケンス

```
【MFA有効化フロー】
1. show - MFA状態確認
   └─ mfa_enabled?, mfa_feature_available?を返却

2. create - MFA有効化開始
   └─ OTPシークレット生成（User.generate_otp_secret）
   └─ usersテーブルのotp_secretを更新
   └─ provisioning_uriを返却（QRコード表示用）

3. verify - TOTP検証と有効化確定
   └─ validate_otpでOTPコード検証
   └─ otp_required_for_loginをtrueに更新
   └─ バックアップコード生成（未生成の場合）
   └─ backup_codesを返却

【MFA無効化フロー】
4. destroy - MFA無効化
   └─ validate_otpでOTPコード検証
   └─ validate_passwordでパスワード検証
   └─ otp_secret, otp_required_for_login, otp_backup_codesをクリア

【バックアップコード再生成フロー】
5. backup_codes - バックアップコード再生成
   └─ validate_otpでOTPコード検証
   └─ 新しいバックアップコード10個生成
   └─ backup_codesを返却
```

### フローチャート

```mermaid
flowchart TD
    A[MFA設定画面] --> B{MFA有効?}
    B -->|No| C[有効化開始 POST /mfa]
    C --> D[OTPシークレット生成]
    D --> E[QRコード表示]
    E --> F[認証アプリで登録]
    F --> G[検証 POST /mfa/verify]
    G --> H{OTP検証成功?}
    H -->|No| I[エラー: 無効なコード]
    H -->|Yes| J[MFA有効化完了]
    J --> K[バックアップコード表示]

    B -->|Yes| L[無効化 DELETE /mfa]
    L --> M[OTP + パスワード入力]
    M --> N{検証成功?}
    N -->|No| O[エラー]
    N -->|Yes| P[MFA無効化完了]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-001 | MFA機能フラグ | ENABLE_MFAがfalseの場合、MFA機能は利用不可 | 全MFA操作 |
| BR-002 | バックアップコード数 | バックアップコードは10個生成 | 初回有効化時、再生成時 |
| BR-003 | バックアップコード形式 | 8文字の16進数大文字 | バックアップコード生成時 |
| BR-004 | コード使い捨て | 使用済みバックアップコードは'XXXXXXXX'に置換 | バックアップコード使用時 |
| BR-005 | 無効化時のパスワード確認 | MFA無効化にはOTPとパスワードの両方が必要 | MFA無効化時 |
| BR-006 | TOTP有効期間 | TOTPコードは30秒間有効（RFC 6238準拠） | TOTP検証時 |

### 計算ロジック

- **OTPシークレット**: `User.generate_otp_secret` でbase32エンコードされた20バイトの乱数
- **TOTP計算**: HMAC-SHA1ベース、30秒タイムステップ、6桁コード（RFC 6238）
- **バックアップコード**: `SecureRandom.hex(4).upcase` で8文字の16進数

## データベース操作仕様

### 操作別データベース影響一覧

| 操作 | 対象テーブル | 操作種別 | 概要 |
|-----|-------------|---------|------|
| MFA有効化開始 | users | UPDATE | otp_secret設定 |
| MFA有効化確定 | users | UPDATE | otp_required_for_login=true, バックアップコード設定 |
| MFA無効化 | users | UPDATE | otp_secret, otp_required_for_login, otp_backup_codesクリア |
| バックアップコード使用 | users | UPDATE | otp_backup_codes更新（使用済みマスク） |

### テーブル別操作詳細

#### users

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| UPDATE | otp_secret | User.generate_otp_secret | MFA有効化開始時、暗号化保存 |
| UPDATE | otp_required_for_login | true/false | MFA有効/無効化時 |
| UPDATE | otp_backup_codes | Array[String] | バックアップコード、暗号化保存 |

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| 403 | Forbidden | MFA機能が無効（環境設定） | 管理者に問い合わせ |
| 422 | Unprocessable Entity | MFA未有効でdestroy/backup_codes実行 | MFA有効化後に再試行 |
| 422 | Unprocessable Entity | MFA有効済みでcreate/verify実行 | 既に有効化済み |
| 422 | Unprocessable Entity | OTPコード不正 | 正しいコード入力 |
| 422 | Unprocessable Entity | パスワード不正（無効化時） | 正しいパスワード入力 |

### リトライ仕様

- OTPコード検証失敗時のリトライ制限なし
- 30秒経過で新しいOTPコードが生成されるため自然にリトライ可能

## トランザクション仕様

- verify_and_activate!はActiveRecord::Transactionで囲まれる
- otp_required_for_loginの更新とバックアップコード生成は原子的に実行

## パフォーマンス要件

- OTP検証処理: 100ms以内
- バックアップコード検証: タイミング攻撃対策のため一定時間（全コード比較）

## セキュリティ考慮事項

- OTPシークレットはActive Record Encryptionで暗号化（deterministic）
- バックアップコードも暗号化保存
- バックアップコード検証はsecure_compareで定時間比較（タイミング攻撃対策）
- MFA無効化にはパスワード再確認が必要
- consumed_timestepで同一OTPの再利用を防止

## 備考

- MFA機能は環境変数`ENABLE_MFA`で有効/無効化可能
- QRコードの表示はフロントエンドで実装（otpauth://URIを使用）
- TOTPの実装はdevise-two-factor gemに依存

---

## コードリーディングガイド

本機能を理解するために参照すべきファイルと、推奨する読み解き順序を以下に示す。

### 推奨読解順序

#### Step 1: データ構造を理解する

MFA関連のデータベースカラムとモデル設定を把握。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | user.rb | `app/models/user.rb` | MFA関連カラム、暗号化設定、deviseモジュール |

**読解のコツ**:
- 10-22行目: otp_secret, otp_backup_codes, otp_required_for_login等のカラム定義
- 67行目: :two_factor_authenticatableモジュール
- 83-84行目: encrypts設定による暗号化

#### Step 2: エントリーポイントを理解する

MFAコントローラーのAPIエンドポイントを把握。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | mfa_controller.rb | `app/controllers/api/v1/profile/mfa_controller.rb` | 各アクションの処理フロー |

**主要処理フロー**:
1. **2-6行目**: before_actionでMFA機能・状態チェック
2. **10-12行目**: createでOTPシークレット生成
3. **14-16行目**: verifyでTOTP検証と有効化
4. **18-20行目**: destroyでMFA無効化
5. **22-24行目**: backup_codesでバックアップコード再生成

#### Step 3: MFA管理サービスを理解する

MFAの有効化・無効化・バックアップコード管理の詳細を把握。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | management_service.rb | `app/services/mfa/management_service.rb` | MFA管理ロジック |

**主要処理フロー**:
- **4-7行目**: enable_two_factor!でOTPシークレット生成
- **9-14行目**: disable_two_factor!でMFA無効化
- **16-21行目**: verify_and_activate!でMFA有効化確定
- **31-36行目**: generate_backup_codes!でバックアップコード生成
- **38-47行目**: validate_backup_code!でバックアップコード検証

#### Step 4: MFA認証サービスを理解する

ログイン時のMFA検証フローを把握。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | authentication_service.rb | `app/services/mfa/authentication_service.rb` | MFA認証ロジック |

**主要処理フロー**:
- **4-11行目**: authenticateでOTP/バックアップコード判定
- **15-17行目**: authenticate_with_otpでTOTP検証
- **19-22行目**: authenticate_with_backup_codeでバックアップコード検証

### プログラム呼び出し階層図

```
Api::V1::Profile::MfaController
    │
    ├─ show
    │      └─ current_user.mfa_enabled?
    │      └─ current_user.mfa_feature_available?
    │      └─ mfa_service.two_factor_provisioning_uri
    │
    ├─ create
    │      └─ Mfa::ManagementService#enable_two_factor!
    │             └─ User.generate_otp_secret
    │             └─ user.save!
    │
    ├─ verify
    │      └─ Mfa::AuthenticationService#authenticate
    │      └─ Mfa::ManagementService#verify_and_activate!
    │             └─ user.update!(otp_required_for_login: true)
    │             └─ generate_backup_codes!
    │
    ├─ destroy
    │      └─ Mfa::AuthenticationService#authenticate
    │      └─ user.valid_password?
    │      └─ Mfa::ManagementService#disable_two_factor!
    │
    └─ backup_codes
           └─ Mfa::AuthenticationService#authenticate
           └─ Mfa::ManagementService#generate_backup_codes!
```

### データフロー図

```
[入力]                    [処理]                         [出力]

[MFA有効化開始]
(なし) ──────────────▶ ManagementService ──────────▶ otp_secret (DB)
                       #enable_two_factor!              │
                                                        ▼
                                                   provisioning_uri (JSON)

[MFA検証・有効化]
otp_code ────────────▶ AuthenticationService ─────▶ otp_required_for_login (DB)
                       #authenticate                    │
                              │                         ▼
                              ▼                    otp_backup_codes (DB)
                       ManagementService                │
                       #verify_and_activate!            ▼
                                                   backup_codes (JSON)

[MFA無効化]
otp_code ────────────▶ AuthenticationService
password                      │
                              ▼
                       ManagementService ─────────▶ otp_secret = nil (DB)
                       #disable_two_factor!            otp_required_for_login = false
                                                       otp_backup_codes = nil
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| mfa_controller.rb | `app/controllers/api/v1/profile/mfa_controller.rb` | コントローラー | MFA設定APIエンドポイント |
| management_service.rb | `app/services/mfa/management_service.rb` | サービス | MFA有効化・無効化・バックアップコード管理 |
| authentication_service.rb | `app/services/mfa/authentication_service.rb` | サービス | MFA認証（TOTP・バックアップコード検証） |
| token_service.rb | `app/services/mfa/token_service.rb` | サービス | MFAトークン管理（ログイン時一時トークン） |
| user.rb | `app/models/user.rb` | モデル | MFA関連カラム・暗号化設定 |
| routes.rb | `config/routes.rb` | 設定 | MFAエンドポイント定義（378-384行目） |
| show.json.jbuilder | `app/views/api/v1/profile/mfa/show.json.jbuilder` | ビュー | MFA状態レスポンステンプレート |
