# 機能設計書 73-レート制限

## 概要

本ドキュメントは、EtherpadにおけるAPIリクエストのレート制限機能の設計を定義する。DDoS攻撃対策およびサービス安定性確保のためのリクエスト制限について記述する。

### 本機能の処理概要

クライアントからのリクエスト頻度を監視し、設定された閾値を超えた場合にリクエストを拒否する機能である。2種類のレート制限が実装されている：インポート/エクスポート用のHTTPレート制限と、リアルタイム編集用のWebSocketレート制限。

**業務上の目的・背景**：Webアプリケーションにおいて、悪意のあるユーザーや攻撃者による大量リクエストはサービス停止やサーバーリソース枯渇を引き起こす可能性がある。本機能により、特定のIPアドレスからの過剰なリクエストを制限し、全ユーザーに対して安定したサービス提供を維持する。また、リアルタイム編集においても過剰な変更送信による負荷を防止する。

**機能の利用シーン**：
- 短時間に大量のファイルインポートを試みるユーザーへの制限
- 連続したエクスポートリクエストの抑制
- 自動化ツールによる過剰な編集操作の制限
- DDoS攻撃からのシステム保護

**主要な処理内容**：
1. HTTPリクエスト用レート制限（express-rate-limit）
   - インポート/エクスポートエンドポイントに適用
   - IPアドレスベースでのリクエスト数カウント
   - 制限超過時は警告ログ出力
2. WebSocket用レート制限（rate-limiter-flexible）
   - リアルタイム編集メッセージに適用
   - 本番環境でのみ適用
   - 制限超過時は接続切断

**関連システム・外部連携**：express-rate-limitライブラリ、rate-limiter-flexibleライブラリを使用。

**権限による制御**：全てのユーザーに対して適用。管理者権限でも制限を受ける。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 2 | パッド編集画面 | 主画面 | インポート/エクスポート操作時にレート制限適用 |
| 3 | タイムスライダー画面 | 補助画面 | エクスポート操作時にレート制限適用 |

## 機能種別

セキュリティ処理 / アクセス制御

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| importExportRateLimiting.windowMs | number | No | レート制限ウィンドウ（ミリ秒） | デフォルト：90000 |
| importExportRateLimiting.max | number | No | ウィンドウ内の最大リクエスト数 | デフォルト：10 |
| commitRateLimiting.duration | number | No | レート制限期間（秒） | デフォルト：1 |
| commitRateLimiting.points | number | No | 期間内の最大ポイント数 | デフォルト：10 |

### 入力データソース

- settings.json: レート制限設定
- HTTPリクエストのIPアドレス
- WebSocket接続のIPアドレス

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| rateLimited | boolean | 制限超過したかどうか |
| retryAfter | number | 再試行可能になるまでの秒数 |

### 出力先

- HTTP 429 Too Many Requests（インポート/エクスポート）
- WebSocket disconnect メッセージ（リアルタイム編集）
- ログ出力（警告メッセージ）

## 処理フロー

### 処理シーケンス

```
1. リクエスト受信
   └─ IPアドレスを取得
2. レート制限チェック
   └─ 現在のカウントと制限値を比較
3. 制限超過判定
   └─ 超過: リクエスト拒否
   └─ 未超過: カウントをインクリメントして処理続行
4. 制限超過時の処理
   └─ HTTP: 429レスポンス返却
   └─ WebSocket: disconnect送信
5. ログ記録
   └─ 制限トリガー時に警告ログ出力
```

### フローチャート

```mermaid
flowchart TD
    A[リクエスト受信] --> B[IPアドレス取得]
    B --> C{レート制限タイプ?}
    C -->|HTTP| D[express-rate-limit]
    C -->|WebSocket| E[rate-limiter-flexible]
    D --> F{制限超過?}
    E --> G{制限超過?}
    F -->|Yes| H[429 Too Many Requests]
    F -->|No| I[リクエスト処理]
    G -->|Yes| J[disconnect: rateLimited]
    G -->|No| K[メッセージ処理]
    H --> L[警告ログ出力]
    J --> L
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-73-01 | インポート/エクスポート制限 | 90秒間に10リクエストまで（デフォルト） | /p/:pad/import, /p/:pad/export へのアクセス |
| BR-73-02 | コミットレート制限 | 1秒間に10変更まで（デフォルト） | USER_CHANGESメッセージ処理時 |
| BR-73-03 | 本番環境限定 | WebSocketレート制限は本番環境でのみ適用 | NODE_ENV === 'production' |
| BR-73-04 | 初回超過ログ | 制限超過した最初のリクエストでのみ警告ログ出力 | current === limit + 1 |
| BR-73-05 | IPベース制限 | 同一IPアドレスからのリクエストをカウント | 全てのレート制限対象リクエスト |

### 計算ロジック

- **レート計算**: 設定されたウィンドウ/期間内のリクエスト数をカウント
- **リセット**: ウィンドウ/期間経過後にカウントをリセット

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

本機能ではデータベース操作は行わない（メモリ内でカウント管理）。

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| 429 | Too Many Requests | インポート/エクスポート制限超過 | 制限期間経過後に再試行 |
| - | WebSocket disconnect | コミットレート制限超過 | ページをリロードして再接続 |

### リトライ仕様

- HTTP: Retry-Afterヘッダーで再試行可能時間を通知
- WebSocket: クライアント側で自動再接続を試行

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

なし

## パフォーマンス要件

- レート制限チェックはミリ秒単位で完了すること
- メモリ使用量は同時接続数に比例
- 大規模環境ではRedis等の外部ストアを検討

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

- IPスプーフィング対策として、trustProxyを適切に設定すること
- プロキシ経由のアクセスではX-Forwarded-Forヘッダーを考慮
- 制限値は本番環境の負荷に応じて調整が必要

## 備考

- express-rate-limitの詳細設定は公式ドキュメントを参照
- rate-limiter-flexibleの詳細設定は公式ドキュメントを参照
- settings.json.templateにデフォルト設定例が記載

---

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

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

### 推奨読解順序

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

レート制限設定のデータ構造を確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | Settings.ts | `src/node/utils/Settings.ts` | importExportRateLimitingとcommitRateLimitingの型定義 |

**読解のコツ**: TypeScriptの型定義で設定可能なパラメータを確認し、デフォルト値も把握する。

#### Step 2: HTTP用レート制限を理解する

インポート/エクスポート機能のレート制限を確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | importexport.ts | `src/node/hooks/express/importexport.ts` | express-rate-limitの設定と適用 |

**主要処理フロー**:
1. **11行目**: express-rate-limitのインポート
2. **16-25行目**: limiterの設定（設定値をスプレッドで適用、ハンドラーで警告ログ出力）
3. **28行目**: エクスポートエンドポイントにlimiter適用
4. **74行目**: インポートエンドポイントにlimiter適用

#### Step 3: WebSocket用レート制限を理解する

リアルタイム編集のレート制限を確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | PadMessageHandler.ts | `src/node/handler/PadMessageHandler.ts` | RateLimiterMemoryの使用 |

**主要処理フロー**:
- **46行目**: RateLimiterMemoryのインポート
- **55行目**: rateLimiter変数の宣言
- **69-74行目**: socketio hookでrateLimiterを初期化
- **276-286行目**: handleMessage内でのレート制限チェック

#### Step 4: 設定のデフォルト値を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | Settings.ts | `src/node/utils/Settings.ts` | レート制限のデフォルト設定値 |

**主要処理フロー**:
- **609-614行目**: importExportRateLimitingのデフォルト値（windowMs: 90000, max: 10）
- **623-628行目**: commitRateLimitingのデフォルト値（duration: 1, points: 10）

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

```
HTTPリクエスト（インポート/エクスポート）
    │
    └─ importexport.ts
           ├─ rateLimit() ミドルウェア [16-25行目]
           │      └─ settings.importExportRateLimiting
           │
           └─ handler (制限超過時) [18-24行目]
                  └─ console.warn()

WebSocketメッセージ
    │
    └─ PadMessageHandler.ts
           ├─ socketio hook [69-74行目]
           │      └─ new RateLimiterMemory(settings.commitRateLimiting)
           │
           └─ handleMessage() [273-286行目]
                  ├─ rateLimiter.consume()
                  └─ socket.emit('message', {disconnect: 'rateLimited'})
```

### データフロー図

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

HTTP Request ─────────▶ express-rate-limit ─────▶ 処理続行 / 429 Error
(IP Address)                  │
                              ▼
                    settings.importExportRateLimiting
                              │
                              ▼
                    console.warn (制限超過時)

WebSocket Message ────▶ RateLimiterMemory ──────▶ 処理続行 / disconnect
(IP Address)                  │
                              ▼
                    settings.commitRateLimiting
                              │
                              ▼
                    messageLogger.warn (制限超過時)
                    stats.meter('rateLimited')
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| importexport.ts | `src/node/hooks/express/importexport.ts` | ソース | HTTPレート制限の実装 |
| PadMessageHandler.ts | `src/node/handler/PadMessageHandler.ts` | ソース | WebSocketレート制限の実装 |
| Settings.ts | `src/node/utils/Settings.ts` | ソース | レート制限設定の定義 |
| settings.json.template | プロジェクトルート | 設定テンプレート | 設定例 |
| package.json | `src/package.json` | 設定 | express-rate-limit, rate-limiter-flexible依存関係 |
