# 機能設計書 8-HtmlSanitizer

## 概要

本ドキュメントは、Symfony HtmlSanitizerコンポーネントの機能設計を記述する。HtmlSanitizerは信頼できないHTML入力を安全にサニタイズするオブジェクト指向APIを提供し、XSS対策としてDOM挿入前のHTML浄化を行う。

### 本機能の処理概要

HtmlSanitizerコンポーネントは、ユーザー提供のHTMLコンテンツから悪意のあるスクリプトや不正な要素・属性を除去し、安全なHTMLに変換するサニタイズ機能を提供する。W3CのHTML仕様に基づく要素リファレンスを内蔵し、許可リスト/ブロックリスト/ドロップリストの3段階で要素・属性の制御を行う。

**業務上の目的・背景**：ユーザー生成コンテンツ（UGC）をWebページに表示する場合、クロスサイトスクリプティング（XSS）攻撃のリスクがある。HtmlSanitizerはHTMLを解析し、安全な要素・属性のみを残すことで、XSS攻撃を防止する。CMS、フォーラム、コメントシステム等で必須のセキュリティ対策である。

**機能の利用シーン**：ユーザー入力HTMLの表示前処理、リッチテキストエディタ出力のサニタイズ、メールHTMLのクリーニング、外部ソースHTMLの安全な表示等で利用される。

**主要な処理内容**：
1. HTML文字列のDOMパース（NativeParser）
2. DOMツリーの走査と各ノードのサニタイズ（DomVisitor）
3. 要素の許可/ブロック/ドロップ判定
4. 属性のフィルタリング（許可属性のみ保持）
5. リンクスキーム制限（http, https, mailto, tel等）
6. メディアスキーム制限（http, https, data等）
7. ホスト名制限（リンク先・メディア元の制限）
8. 強制属性の付加
9. テキストコンテキストでのHTMLエンティティエンコード
10. 入力長制限によるDoS防止

**関連システム・外部連携**：FrameworkBundle（DI設定による統合）

**権限による制御**：権限制御なし（サニタイズポリシーはHtmlSanitizerConfigで静的に設定）。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|

HtmlSanitizerは画面機能マッピングに直接関連する画面がない。

## 機能種別

セキュリティ / データ浄化 / XSS対策

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| input | string | Yes | サニタイズ対象のHTML文字列 | UTF-8チェック、NULL文字除去 |
| element | string | No | サニタイズコンテキスト要素（sanitizeFor用） | W3Cリファレンスの要素名 |

### 入力データソース

- ユーザー提供のHTML文字列

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| sanitizedHtml | string | サニタイズ済みのHTML文字列 |

### 出力先

- 文字列として返却

## 処理フロー

### 処理シーケンス

```
1. sanitize() / sanitizeFor()呼び出し
   └─ コンテキスト要素の特定（body/head/text）
2. テキストコンテキスト判定
   └─ テキストコンテキストの場合はHTMLエンティティエンコードのみで早期リターン
3. 入力長チェック
   └─ maxInputLengthを超える場合は切り詰め
4. UTF-8妥当性チェック
   └─ 不正なUTF-8の場合は空文字列を返却
5. NULL文字除去
   └─ \0を置換文字(U+FFFD)に置換
6. HTMLパース
   └─ NativeParser::parse()でDOMDocumentを生成
7. DOMツリー走査・サニタイズ
   └─ DomVisitorが各ノードを走査し、設定に基づきフィルタリング
8. サニタイズ済みHTML出力
   └─ 安全なDOMをHTML文字列にレンダリング
```

### フローチャート

```mermaid
flowchart TD
    A[HTML入力] --> B{テキストコンテキスト?}
    B -->|Yes| C[HTMLエンティティエンコード]
    C --> D[返却]
    B -->|No| E{maxInputLength超過?}
    E -->|Yes| F[入力切り詰め]
    E -->|No| G{UTF-8妥当?}
    F --> G
    G -->|No| H[空文字返却]
    G -->|Yes| I[NULL文字除去]
    I --> J[NativeParser::parse]
    J --> K{パース成功?}
    K -->|No| H
    K -->|Yes| L[DomVisitor::visit]
    L --> M[ノードごとの判定]
    M --> N{Allow/Block/Drop?}
    N -->|Allow| O[要素保持 + 属性フィルタ]
    N -->|Block| P[要素除去 + 子要素保持]
    N -->|Drop| Q[要素 + 子要素すべて除去]
    O --> R[サニタイズ済みHTML]
    P --> R
    Q --> R
    R --> D
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-01 | デフォルトアクションはDrop | 設定されていない要素はデフォルトでドロップ（除去）される | HtmlSanitizerConfig未設定の要素 |
| BR-02 | Allow/Block/Dropの3段階 | Allowは要素と許可属性を保持、Blockは要素を除去し子要素を保持、Dropは要素と子要素を完全除去 | 各要素の設定に応じて |
| BR-03 | リンクスキーム制限 | デフォルトでhttp, https, mailto, telのみ許可 | href属性のあるリンク要素 |
| BR-04 | メディアスキーム制限 | デフォルトでhttp, https, dataのみ許可 | src属性のあるメディア要素 |
| BR-05 | 相対リンクのデフォルト拒否 | デフォルトで相対リンクはドロップされる | allowRelativeLinks=false（デフォルト） |
| BR-06 | Head/Body分離 | head要素とbody要素の許可リストは分離して管理される | sanitizeFor()のコンテキストに応じて |
| BR-07 | DoS防止 | maxInputLength(-1で無制限)による入力長制限 | 常時 |

### 計算ロジック

特になし。

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

HtmlSanitizerコンポーネントはデータベース操作を行わない。

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | - | 不正なUTF-8入力 | 空文字列を返却（例外はスローしない） |
| - | - | パース失敗 | 空文字列を返却（例外はスローしない） |

### リトライ仕様

リトライ機能なし。

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

トランザクション管理なし。

## パフォーマンス要件

- DomVisitorはコンテキストごとにキャッシュされる（`$this->domVisitors[$context]`）
- maxInputLengthによる入力長制限でDoS攻撃を緩和

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

- **XSS防止**: 信頼できないHTML入力から悪意のあるスクリプトを除去する主要機能
- **NULL文字対策**: NULL文字をU+FFFDに置換してバイパス攻撃を防止（行70）
- **UTF-8検証**: 不正なUTF-8文字列はIE6のXSS脆弱性を利用される可能性があるため拒否（行63-67）
- **リンクスキーム制限**: javascript:等の危険なスキームをブロック
- **DoS防止**: 極端に長いHTML文字列による処理遅延を入力長制限で防止（行59-61）

## 備考

- W3CReference内部リファレンスにより、HTML仕様に準拠した要素・属性の管理が可能
- AttributeSanitizerInterfaceによるカスタム属性サニタイザーの追加が可能
- TextSanitizer::StringSanitizerによるHTML文字列のケース変換・エンティティエンコードを提供

---

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

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | HtmlSanitizerConfig.php | `src/Symfony/Component/HtmlSanitizer/HtmlSanitizerConfig.php` | サニタイズ設定。許可要素、ブロック要素、ドロップ要素、リンク/メディアスキーム制限等 |
| 1-2 | HtmlSanitizerAction.php | `src/Symfony/Component/HtmlSanitizer/HtmlSanitizerAction.php` | Allow/Block/Dropのenum定義 |
| 1-3 | Reference/W3CReference.php | `src/Symfony/Component/HtmlSanitizer/Reference/W3CReference.php` | W3C HTML要素リファレンス（HEAD_ELEMENTS, BODY_ELEMENTS, CONTEXTS_MAP等） |

**読解のコツ**: HtmlSanitizerConfigの各プロパティ（行22-69で定義）がサニタイズポリシーの全設定項目を表す。`defaultAction`がDrop（行22）であることが、ホワイトリスト方式の根拠。

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | HtmlSanitizer.php | `src/Symfony/Component/HtmlSanitizer/HtmlSanitizer.php` | サニタイズ処理のメインクラス |

**主要処理フロー**:
1. **39-42行目**: sanitize()メソッド - CONTEXT_BODYでsanitizeFor()を呼び出す
2. **44-79行目**: sanitizeFor()メソッド - コンテキスト判定、UTF-8検証、NULL除去、パース、DomVisitor走査
3. **59-61行目**: maxInputLength制限チェック
4. **65-67行目**: UTF-8妥当性検証（preg_matchによるサイレントチェック）
5. **70行目**: NULL文字置換
6. **87-134行目**: createDomVisitorForContext() - Head/Bodyコンテキストに応じたDomVisitor生成

#### Step 3: DOM走査処理を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | Visitor/DomVisitor.php | `src/Symfony/Component/HtmlSanitizer/Visitor/DomVisitor.php` | DOMツリー走査とサニタイズ処理 |
| 3-2 | Visitor/AttributeSanitizer/ | `src/Symfony/Component/HtmlSanitizer/Visitor/AttributeSanitizer/` | 属性サニタイザー群 |

#### Step 4: パーサーを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | Parser/NativeParser.php | `src/Symfony/Component/HtmlSanitizer/Parser/NativeParser.php` | PHPネイティブDOMParserを使用したHTML解析 |

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

```
HtmlSanitizer::sanitize(input)
    |
    +-- HtmlSanitizer::sanitizeFor('body', input)
            |
            +-- StringSanitizer::htmlLower(element)
            +-- W3CReference::CONTEXTS_MAP[element]  [コンテキスト特定]
            |
            +-- [テキストコンテキスト] StringSanitizer::encodeHtmlEntities(input)
            |
            +-- [maxInputLength チェック]
            +-- [UTF-8 妥当性チェック]
            +-- [NULL文字除去]
            |
            +-- NativeParser::parse(input, element)
            |       +-- DOMDocument::loadHTML()
            |
            +-- DomVisitor::visit(parsedDom)
                    |
                    +-- [各ノードを走査]
                    +-- [Allow] 要素保持 + 属性フィルタリング
                    +-- [Block] 子要素を親にマージ
                    +-- [Drop] ノード完全除去
                    |
                    +-- render()  [HTML文字列に変換]
```

### データフロー図

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

HTML文字列              --->  UTF-8検証 + NULL除去          --->  クリーン入力
                              |
                              v
                     NativeParser::parse()           --->  DOMDocument
                              |
                              v
                     DomVisitor::visit()             --->  サニタイズ済みDOM
                              |
                              v
                     render()                        --->  安全なHTML文字列
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| HtmlSanitizer.php | `src/Symfony/Component/HtmlSanitizer/HtmlSanitizer.php` | ソース | サニタイズ処理のメインクラス |
| HtmlSanitizerInterface.php | `src/Symfony/Component/HtmlSanitizer/HtmlSanitizerInterface.php` | ソース | サニタイザーインターフェース |
| HtmlSanitizerConfig.php | `src/Symfony/Component/HtmlSanitizer/HtmlSanitizerConfig.php` | ソース | サニタイズ設定 |
| HtmlSanitizerAction.php | `src/Symfony/Component/HtmlSanitizer/HtmlSanitizerAction.php` | ソース | Allow/Block/Drop enum |
| Reference/W3CReference.php | `src/Symfony/Component/HtmlSanitizer/Reference/W3CReference.php` | ソース | W3C HTML要素リファレンス |
| Parser/NativeParser.php | `src/Symfony/Component/HtmlSanitizer/Parser/NativeParser.php` | ソース | HTMLパーサー |
| Parser/ParserInterface.php | `src/Symfony/Component/HtmlSanitizer/Parser/ParserInterface.php` | ソース | パーサーインターフェース |
| Visitor/DomVisitor.php | `src/Symfony/Component/HtmlSanitizer/Visitor/DomVisitor.php` | ソース | DOM走査・サニタイズ処理 |
| Visitor/AttributeSanitizer/ | `src/Symfony/Component/HtmlSanitizer/Visitor/AttributeSanitizer/` | ソース | 属性サニタイザー群 |
| TextSanitizer/ | `src/Symfony/Component/HtmlSanitizer/TextSanitizer/` | ソース | テキストサニタイズユーティリティ |
