# 通知設計書 25-CrumbセッションID除外警告

## 概要

本ドキュメントは、CSRF保護のCrumb生成においてセッションIDが除外されている場合に管理者へセキュリティ警告を表示する通知機能（ExcludeSessionIdAdministrativeMonitor）の設計仕様を定義する。

### 本通知の処理概要

本通知は、JenkinsのCSRF保護機能であるCrumb生成において、システムプロパティ（`hudson.security.csrf.DefaultCrumbIssuer.EXCLUDE_SESSION_ID`）によりセッションIDが除外されている場合に、セキュリティ警告を表示する機能である。

**業務上の目的・背景**：CrumbはCSRF（Cross-Site Request Forgery）攻撃を防ぐためのトークンである。従来はクライアントIPアドレスをCrumb生成に使用していたが、プロキシ環境での問題から廃止された。現在はセッションIDを使用してCrumbを生成している。セッションIDも除外すると、CSRF保護が大幅に弱体化するため、この設定が有効な場合は管理者に警告を表示する必要がある。

**通知の送信タイミング**：管理画面へのアクセス時に、DefaultCrumbIssuerが使用されており、かつEXCLUDE_SESSION_IDがtrueの場合に警告が表示される。

**通知の受信者**：Jenkins管理者が管理画面を閲覧した際に表示される。

**通知内容の概要**：セッションIDがCrumb生成から除外されているため、CSRF保護が弱体化していることを示す警告メッセージが表示される。

**期待されるアクション**：管理者はシステムプロパティを削除するか、CSRF保護についてのドキュメントを参照して適切な対策を講じる。

## 通知種別

アプリ内通知（Jenkins管理画面への警告バナー表示） - セキュリティ警告

## 送信仕様

### 基本情報

| 項目 | 内容 |
|-----|------|
| 送信方式 | 同期（画面アクセス時にチェック） |
| 優先度 | 高（セキュリティ警告） |
| リトライ | 無し |

### 送信先決定ロジック

AdministrativeMonitorとして実装されているため、`/manage`画面にアクセスした管理者に対して表示される。表示条件は以下の通り：
- JenkinsのCrumbIssuerがDefaultCrumbIssuerであること
- EXCLUDE_SESSION_IDシステムプロパティがtrueであること

## 通知テンプレート

### 画面通知の場合

| 項目 | 内容 |
|-----|------|
| 表示名 | Warn when session ID is excluded from Default Crumb Issuer |
| 表示位置 | 管理画面のAdministrativeMonitorセクション |
| 形式 | セキュリティ警告バナー |

### 本文テンプレート

```
Jenkins no longer uses the client IP address as part of CSRF protection.
This controller is configured to also not use the session ID, which is even less safe now.
This option will be removed in future releases.
```

### 添付ファイル

該当なし

## テンプレート変数

該当なし（固定メッセージ）

## 送信トリガー・条件

### トリガー一覧

| トリガー種別 | トリガーイベント | 送信条件 | 説明 |
|------------|----------------|---------|------|
| 画面操作 | 管理画面アクセス | DefaultCrumbIssuer使用かつEXCLUDE_SESSION_ID=true | セキュリティ警告として表示 |

### 送信抑止条件

| 条件 | 説明 |
|-----|------|
| CrumbIssuerがDefaultCrumbIssuer以外 | 対象外 |
| EXCLUDE_SESSION_IDがfalse | 正常な状態 |
| ユーザーがDismissした場合 | モニターを無効化 |

## 処理フロー

### 送信フロー

```mermaid
flowchart TD
    A[管理画面アクセス] --> B[CrumbIssuer取得]
    B --> C{DefaultCrumbIssuer?}
    C -->|No| I[表示なし]
    C -->|Yes| D{EXCLUDE_SESSION_ID?}
    D -->|false| I
    D -->|true| E[セキュリティ警告表示]
    E --> F{ユーザーアクション?}
    F -->|Learn| G[外部リンクへ遷移]
    F -->|Dismiss| H[モニター無効化]
    G --> I[終了]
    H --> I
```

## データベース参照・更新仕様

### 参照テーブル一覧

該当なし

### 参照データ

| データ | 内容 |
|--------|------|
| EXCLUDE_SESSION_ID | システムプロパティ（静的フィールド） |

### 更新対象

| 対象 | 操作 | 概要 |
|------|------|------|
| モニター設定 | UPDATE | disable(true)で無効化 |

## エラー処理

### エラーケース一覧

| エラー種別 | 発生条件 | 対処方法 |
|----------|---------|---------|
| 設定保存失敗 | ファイルシステムエラー | IOException発生 |

### リトライ仕様

| 項目 | 内容 |
|-----|------|
| リトライ回数 | 0 |
| リトライ間隔 | - |
| リトライ対象エラー | - |

## 配信設定

### レート制限

| 項目 | 内容 |
|-----|------|
| 1分あたり上限 | 制限なし |
| 1日あたり上限 | 制限なし |

### 配信時間帯

制限なし（管理画面アクセス時に表示）

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

- `isSecurity()`がtrueを返すため、セキュリティ警告として扱われる
- 外部リンク（jenkins.io/redirect/csrf-protection/）へのリダイレクトを含む
- EXCLUDE_SESSION_IDの設定自体がセキュリティリスクであることを警告
- 将来のリリースでこのオプションは削除予定

## 備考

- DefaultCrumbIssuerの内部クラスとして実装されている
- @Restrictedで外部利用が制限されている
- 従来のexcludeClientIPFromCrumbオプションは既に非推奨

---

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

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

### 推奨読解順序

#### Step 1: 背景を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | DefaultCrumbIssuer.java | `core/src/main/java/hudson/security/csrf/DefaultCrumbIssuer.java` | EXCLUDE_SESSION_IDフィールド（49-51行目） |

**読解のコツ**: 静的フィールドEXCLUDE_SESSION_IDはシステムプロパティから初期化される。@SuppressFBWarningsでGroovy Console用に非finalにされている。

#### Step 2: Crumb生成ロジックを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | DefaultCrumbIssuer.java | `core/src/main/java/hudson/security/csrf/DefaultCrumbIssuer.java` | issueCrumb()メソッド（101-120行目） |

**主要処理フロー**:
1. **108-109行目**: ユーザー名をバッファに追加
2. **110-113行目**: EXCLUDE_SESSION_IDがfalseの場合のみセッションIDを追加
3. **115-116行目**: SHA-256でハッシュ化

#### Step 3: モニター実装を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | DefaultCrumbIssuer.java | `core/src/main/java/hudson/security/csrf/DefaultCrumbIssuer.java` | ExcludeSessionIdAdministrativeMonitor内部クラス（161-195行目） |

**主要処理フロー**:
1. **165-172行目**: isActivated() - DefaultCrumbIssuer使用かつEXCLUDE_SESSION_ID=trueでtrue
2. **174-177行目**: isSecurity() - 常にtrueを返す
3. **184-193行目**: doAct() - learnパラメータで外部リンク、dismissでモニター無効化

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

```
Jenkins管理画面 (/manage)
    │
    └─ DefaultCrumbIssuer.ExcludeSessionIdAdministrativeMonitor
           │
           ├─ isActivated()
           │      ├─ Jenkins.get().getCrumbIssuer()
           │      └─ EXCLUDE_SESSION_ID チェック
           │
           ├─ isSecurity()
           │      └─ return true
           │
           ├─ getDisplayName()
           │
           └─ doAct() (POSTリクエスト)
                  ├─ learn → sendRedirect("https://...")
                  └─ dismiss → disable(true)
```

### データフロー図

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

システムプロパティ ────▶ EXCLUDE_SESSION_ID ──┐
                                              │
Jenkins.getCrumbIssuer() ─────────────────────┼─▶ isActivated()
                                              │         │
                                              │         ▼
                                              │  ┌─────────────────────┐
                                              │  │ DefaultCrumbIssuer  │
                                              │  │ かつ                │
                                              │  │ EXCLUDE_SESSION_ID  │
                                              └──│ = true で表示       │
                                                 └─────────────────────┘
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| DefaultCrumbIssuer.java | `core/src/main/java/hudson/security/csrf/DefaultCrumbIssuer.java` | ソース | メインモニター実装（内部クラス） |
| CrumbIssuer.java | `core/src/main/java/hudson/security/csrf/CrumbIssuer.java` | ソース | 基底クラス |
| DefaultCrumbIssuerTest.java | `test/src/test/java/hudson/security/csrf/DefaultCrumbIssuerTest.java` | テスト | 単体テスト |
