# 機能設計書 74-CAPTCHA検証

## 概要

本ドキュメントは、Shopwareストアフロントにおけるベーシックキャプチャ（CAPTCHA）検証機能の設計を記載する。フォーム送信時のボット攻撃を防止するためのセキュリティ機能である。

### 本機能の処理概要

CAPTCHA検証機能は、自動化されたボットによるフォーム送信を防止するためのセキュリティ機構である。画像に表示された文字を入力させることで、人間によるアクセスであることを確認する。Shopwareでは「ベーシックキャプチャ」として独自のCAPTCHA実装を提供している。

**業務上の目的・背景**：ECサイトはボットによるスパム送信、自動アカウント作成、不正注文などの攻撃対象となりやすい。CAPTCHA検証はこれらの自動化攻撃を防ぐ第一の防壁として機能する。Google reCAPTCHAなどの外部サービスへの依存を避けたい場合に、独自のCAPTCHA機能が重要となる。

**機能の利用シーン**：
- お問い合わせフォーム送信時のボット防止
- アカウント登録フォームでの自動登録防止
- ニュースレター登録でのスパム登録防止
- ログインフォームでのブルートフォース攻撃対策

**主要な処理内容**：
1. CAPTCHA画像の生成（ランダム文字列と歪んだ画像）
2. セッションへのCAPTCHAコード保存
3. フォーム送信時のCAPTCHA入力値検証
4. 検証結果のレスポンス返却

**関連システム・外部連携**：
- セッション管理サービス
- 画像生成サービス（GDライブラリ）
- システム設定サービス（CAPTCHA有効/無効）

**権限による制御**：
- CAPTCHAの有効/無効は管理画面で設定可能
- 特定のフォームに対してCAPTCHAを適用可能

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 12 | ログイン/登録ページ | 参照画面 | CAPTCHA付きログイン/登録フォーム |
| 26 | CMSページ（ウィジェット） | 参照画面 | CAPTCHA付きお問い合わせフォーム |

## 機能種別

バリデーション / セキュリティ

## 入力仕様

### 入力パラメータ

#### CAPTCHA画像取得

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| formId | string | No | フォーム識別子（セッションキー用） | 文字列 |

#### CAPTCHA検証

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| formId | string | Yes | フォーム識別子 | 空文字不可 |
| shopware_basic_captcha_confirm | string | Yes | ユーザー入力のCAPTCHAコード | 文字列 |

### 入力データソース

- クエリパラメータ：formId（CAPTCHA取得時）
- POSTリクエストボディ：formId, shopware_basic_captcha_confirm（検証時）
- セッション：保存されたCAPTCHAコード
- システム設定：CAPTCHA有効/無効設定

## 出力仕様

### 出力データ（CAPTCHA画像取得）

| 項目名 | 型 | 説明 |
|--------|-----|------|
| HTML | string | CAPTCHA画像を含むHTMLフラグメント |

### 出力データ（CAPTCHA検証）

| 項目名 | 型 | 説明 |
|--------|-----|------|
| session | string | 検証成功時：新しいセッション値 |
| type | string | 検証失敗時：danger |
| error | string | 検証失敗時：invalid_captcha |

### 出力先

- CAPTCHA画像：HTMLレスポンス（Twigテンプレートレンダリング）
- CAPTCHA検証：JSONレスポンス

## 処理フロー

### 処理シーケンス（CAPTCHA画像取得）

```
1. リクエスト受信
   └─ CaptchaController::loadBasicCaptcha がGETリクエストを受け取る

2. formId取得
   └─ クエリパラメータからformIdを取得

3. CAPTCHA生成
   └─ BasicCaptchaPageletLoader::load でCAPTCHAを生成
       └─ BasicCaptchaGenerator::generate でランダム文字列と画像を生成

4. セッション保存
   └─ formId + 'basic_captcha_session' をキーとしてセッションにコード保存

5. HTML返却
   └─ basicCaptchaImage.html.twigをレンダリングして返却
```

### 処理シーケンス（CAPTCHA検証）

```
1. リクエスト受信
   └─ CaptchaController::validate がPOSTリクエストを受け取る

2. formId取得
   └─ formIdパラメータを取得（必須）

3. CAPTCHA検証
   └─ BasicCaptcha::isValid でユーザー入力とセッション値を比較
       └─ 大文字小文字を無視した比較

4. セッション更新
   ├─ 検証成功：新しい値をセッションに設定
   └─ 検証失敗：セッション値を削除

5. レスポンス返却
   ├─ 検証成功：session値を含むJSONを返却
   └─ 検証失敗：エラー情報を含むJSONを返却
```

### フローチャート

```mermaid
flowchart TD
    subgraph CAPTCHA画像取得
        A1[GET /basic-captcha] --> B1[formId取得]
        B1 --> C1[CAPTCHA生成]
        C1 --> D1[セッション保存]
        D1 --> E1[HTML返却]
    end

    subgraph CAPTCHA検証
        A2[POST /basic-captcha-validate] --> B2{formId存在?}
        B2 -->|No| C2[エラー: パラメータ不足]
        B2 -->|Yes| D2[セッション値取得]
        D2 --> E2{入力値とセッション値比較}
        E2 -->|一致| F2[成功: 新セッション値設定]
        E2 -->|不一致| G2[失敗: エラーレスポンス]
        F2 --> H2[JSONレスポンス]
        G2 --> H2
    end
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-74-01 | CAPTCHA有効化 | システム設定で有効化されたCAPTCHAのみ検証対象 | フォーム送信時 |
| BR-74-02 | 大文字小文字無視 | CAPTCHAコードの比較は大文字小文字を区別しない | 検証時 |
| BR-74-03 | ワンタイム使用 | CAPTCHAコードは検証後にセッションから削除（再利用不可） | 検証後 |
| BR-74-04 | フォームID連携 | 複数フォームが存在する場合、formIdで識別 | 複数フォーム表示時 |
| BR-74-05 | POSTリクエスト限定 | CAPTCHA検証が必要なのはPOSTリクエストのみ | supports判定時 |

### 計算ロジック

- CAPTCHAコード比較：`strtolower(入力値) === strtolower(セッション値)`

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

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

| 操作 | 対象テーブル | 操作種別 | 概要 |
|-----|-------------|---------|------|
| 設定取得 | system_config | SELECT | CAPTCHA有効/無効設定の取得 |

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

#### system_config

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| SELECT | configuration_value | WHERE configuration_key = 'core.basicInformation.activeCaptchasV2' | CAPTCHAの有効設定取得 |

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| MISSING_REQUEST_PARAMETER | バリデーションエラー | formIdが不足 | 400エラーを返却 |
| captcha.basic-captcha-invalid | CAPTCHA検証エラー | 入力値がセッション値と不一致 | エラーメッセージを表示、新しいCAPTCHAを表示 |

### リトライ仕様

- CAPTCHA検証失敗時：新しいCAPTCHA画像を取得して再入力
- セッションタイムアウト時：ページをリロードして新しいCAPTCHAを取得

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

- セッション操作のみでデータベーストランザクション不要
- セッションの整合性はPHPセッションハンドラーに依存

## パフォーマンス要件

- CAPTCHA画像生成：200ms以内
- CAPTCHA検証：50ms以内

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

- **ワンタイム使用**：CAPTCHAコードは検証後に削除（リプレイ攻撃防止）
- **セッション保存**：CAPTCHAコードはサーバーサイドセッションに保存（クライアントに露出しない）
- **画像の歪み**：OCRによる自動解読を困難にする
- **有効期限**：セッションタイムアウトでCAPTCHAも無効化

## 備考

- Shopwareは複数のCAPTCHA実装をサポート（BasicCaptcha、GoogleReCaptchaV2、GoogleReCaptchaV3、HoneypotCaptcha）
- 本設計書はBasicCaptcha（独自実装）を対象とする
- Google reCAPTCHAを使用する場合は別途設定が必要

---

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

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

### 推奨読解順序

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

まず、CAPTCHAの抽象クラスとインターフェースを理解することが重要。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | AbstractCaptcha.php | `src/Storefront/Framework/Captcha/AbstractCaptcha.php` | CAPTCHAの基底クラス（supports, isValid, getName, shouldBreak） |
| 1-2 | BasicCaptchaPagelet.php | `src/Storefront/Pagelet/Captcha/BasicCaptchaPagelet.php` | CAPTCHAページレットの構造 |

**読解のコツ**: AbstractCaptchaはテンプレートメソッドパターンを使用。supportsメソッドはCAPTCHAが適用されるかどうかを判定、isValidメソッドは検証ロジックを実装。

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

処理の起点となるコントローラーを特定。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | CaptchaController.php | `src/Storefront/Controller/CaptchaController.php` | ストアフロント側のエントリーポイント |

**主要処理フロー**:
1. **36行目**: `/basic-captcha`ルート定義（CAPTCHA画像取得）
2. **37-47行目**: `loadBasicCaptcha`メソッド
3. **39行目**: formIdの取得
4. **40行目**: BasicCaptchaPageletLoaderの呼び出し
5. **41行目**: セッションへのCAPTCHAコード保存
6. **49行目**: `/basic-captcha-validate`ルート定義（CAPTCHA検証）
7. **50-71行目**: `validate`メソッド
8. **53-56行目**: formIdパラメータのバリデーション
9. **58行目**: BasicCaptcha::isValidの呼び出し
10. **59-62行目**: 検証成功時のセッション更新
11. **65-68行目**: 検証失敗時のエラーレスポンス

#### Step 3: CAPTCHA実装を理解する

BasicCaptchaの具体的な実装を確認。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | BasicCaptcha.php | `src/Storefront/Framework/Captcha/BasicCaptcha.php` | ベーシックキャプチャの実装 |

**主要処理フロー**:
- **18-21行目**: 定数定義（CAPTCHA_NAME, CAPTCHA_REQUEST_PARAMETER, BASIC_CAPTCHA_SESSION）
- **35-50行目**: `supports`メソッド - CAPTCHA適用判定
- **41行目**: システム設定からCAPTCHA有効設定を取得
- **47-49行目**: POSTリクエストかつCAPTCHA有効の場合にtrue
- **55-72行目**: `isValid`メソッド - 入力値検証
- **57-61行目**: 入力値の取得とnullチェック
- **63-65行目**: セッションからCAPTCHAコードを取得し、即座に削除
- **71行目**: 大文字小文字を無視した比較

#### Step 4: CAPTCHA生成を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | BasicCaptchaPageletLoader.php | `src/Storefront/Pagelet/Captcha/BasicCaptchaPageletLoader.php` | ページレットローダー |
| 4-2 | AbstractBasicCaptchaGenerator.php | `src/Storefront/Framework/Captcha/BasicCaptcha/AbstractBasicCaptchaGenerator.php` | CAPTCHA画像生成の抽象クラス |

**読解のコツ**: BasicCaptchaPageletLoaderはBasicCaptchaGeneratorを使用してCAPTCHAを生成し、イベントをディスパッチする。

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

```
CaptchaController::loadBasicCaptcha (CAPTCHA画像取得)
    │
    ├─ request->query->get('formId')
    │
    ├─ BasicCaptchaPageletLoader::load
    │      │
    │      ├─ new BasicCaptchaPagelet()
    │      │
    │      ├─ BasicCaptchaGenerator::generate
    │      │      └─ ランダム文字列と画像生成
    │      │
    │      └─ eventDispatcher::dispatch(BasicCaptchaPageletLoadedEvent)
    │
    └─ session->set(formId + 'basic_captcha_session', code)

CaptchaController::validate (CAPTCHA検証)
    │
    ├─ RequestParamHelper::get(request, 'formId')
    │
    ├─ BasicCaptcha::isValid
    │      │
    │      ├─ request->request->get('shopware_basic_captcha_confirm')
    │      │
    │      ├─ session->get(formId + 'basic_captcha_session')
    │      │
    │      ├─ session->remove(formId + 'basic_captcha_session')
    │      │
    │      └─ strtolower比較
    │
    └─ JsonResponse
           ├─ 成功: {session: fakeSession}
           └─ 失敗: {type: 'danger', error: 'invalid_captcha'}
```

### データフロー図

```
[CAPTCHA画像取得]

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

formId ─────────────▶ CaptchaController   ───▶ BasicCaptchaPageletLoader
                              │                         │
                              │                         ▼
                              │                  BasicCaptchaGenerator
                              │                         │
                              │                         └──▶ セッション保存
                              ▼                                    │
                         HTMLレスポンス ◀──────────────────────────┘
                    (CAPTCHA画像)

[CAPTCHA検証]

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

formId ─────────────┐
                    │
captcha_confirm ────┼──▶ CaptchaController   ───▶ BasicCaptcha::isValid
                    │         │                         │
                    │         │                         ├──▶ セッション取得
                    │         │                         │
                    │         │                         └──▶ セッション削除
                              ▼                                    │
                         JsonResponse ◀────────────────────────────┘
                    (success/danger)
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| CaptchaController.php | `src/Storefront/Controller/CaptchaController.php` | コントローラー | ストアフロントのエントリーポイント |
| AbstractCaptcha.php | `src/Storefront/Framework/Captcha/AbstractCaptcha.php` | 抽象クラス | CAPTCHA基底クラス |
| BasicCaptcha.php | `src/Storefront/Framework/Captcha/BasicCaptcha.php` | 実装クラス | ベーシックキャプチャ実装 |
| AbstractBasicCaptchaPageletLoader.php | `src/Storefront/Pagelet/Captcha/AbstractBasicCaptchaPageletLoader.php` | 抽象クラス | ページレットローダー基底 |
| BasicCaptchaPageletLoader.php | `src/Storefront/Pagelet/Captcha/BasicCaptchaPageletLoader.php` | ローダー | ページレット読み込み |
| BasicCaptchaPagelet.php | `src/Storefront/Pagelet/Captcha/BasicCaptchaPagelet.php` | ページレット | CAPTCHAデータ構造 |
| AbstractBasicCaptchaGenerator.php | `src/Storefront/Framework/Captcha/BasicCaptcha/AbstractBasicCaptchaGenerator.php` | 抽象クラス | CAPTCHA画像生成基底 |
| basicCaptchaImage.html.twig | `src/Storefront/Resources/views/storefront/component/captcha/basicCaptchaImage.html.twig` | テンプレート | CAPTCHA画像表示 |
| SystemConfigService.php | `src/Core/System/SystemConfig/SystemConfigService.php` | サービス | システム設定取得 |
