# 誤検知の測り方と閾値の決め方

「300秒に100ファイル」は、デモでは正しく見えます。実際の業務では、バックアップ、全文検索のインデックス作成、分析作業、データ移行が同じ形をしています。**閾値は、導入先の正常な業務ログで測ってから決めるものです。**

このドキュメントは、その測定を AI Secure 自身で行う手順と、同梱の合成データで実際に測った結果です。

## 手順

```bash
# 1. 正常業務の合成トラフィックを作る（事案なし × 3、事案あり × 1）
for s in 1 2 3; do
  python3 -m aisecure baseline --name normal-$s --seed $s --days 5 --users 40 --out normal-$s.json
done
python3 -m aisecure baseline --name incident --seed 9 --days 5 --users 40 --attack --out incident.json

# 2. 検知・誤検知を数え、閾値をスイープする
python3 -m aisecure evaluate normal-*.json incident.json --sweep --out report.md

# 3. 決めた閾値で起動する（設定は監査記録に残ります）
python3 -m aisecure --rules rules.json serve
```

`--save-rules rules.json` を付けると、スイープの推奨値をそのまま設定ファイルとして書き出します。

実ログで測る場合は、手順1のかわりに `aisecure import`（`docs/CONNECTORS.md`）で **事案が起きていないと分かっている期間** を取り込み、`snapshot` をシナリオ形式に包んでラベルを空にしてください。正常期間だけを測れば、そこで出た検知はすべて誤検知です。

## 数え方

| 用語 | 定義 |
|---|---|
| 検知（TP） | 検知結果の根拠イベントIDに、ラベル付き事案のイベントが1つ以上含まれる |
| 誤検知（FP） | 行動系ルール（AS-002 / AS-003 / AS-004）の検知のうち、事案のイベントを1つも含まないもの |
| 検知漏れ（FN） | 事案に対して期待したルールが1件も一致しなかった |
| 精度計算外 | AS-001（未適用パッチ）と AS-005（資産情報の不足）。台帳の登録内容をそのまま示すものなので、事案ラベルと照合しても意味がありません。件数だけ報告します |

「1日あたり何件が人の確認対象になるか」を最終的な判断材料にしています。適合率よりも、運用体制で処理できる件数かどうかが重要だからです。

## 合成データでの測定結果

シナリオ4件（正常のみ3件＋事案あり1件）、40ユーザー×5日ずつ、合計 18.84日・85,509イベント。正常側にはバックアップ、分析作業、移行作業、検索インデックス、週次ウイルススキャン、eDiscovery、バッチETL、承認済み保守を含みます。既定の閾値（300秒 / 100ファイル / 30分）。

| 指標 | 値 |
|---|---|
| 検知 | 3 |
| 誤検知 | 111 |
| 検知漏れ | 0 / 3 |
| 誤検知 / 日 | 5.89 |

ルール別に分けると、性質がはっきり分かれます。

| ルール | 件数 | 検知 | 誤検知 |
|---|---|---|---|
| AS-002 特権ログインの条件 | 10 | 1 | 9 |
| AS-003 短時間の大量ファイル参照 | 103 | 1 | 102 |
| AS-004 相関（機器＋ログイン＋大量参照） | 1 | 1 | 0 |

**AS-003 単体は使えません。** 誤検知102件の中身は、夜間バックアップ、検索インデックスの夜間走査、週次ウイルススキャン、分析担当者の一括参照、移行作業、eDiscovery、バッチETLです。いずれも正常業務であり、量だけでは区別できません。正常側のノイズを増やすほど、この数は増えます。

**AS-004（相関）は、この18.8日間・85,509イベントでも誤検知0件でした。** 公開かつ未修正の接続機器、承認・端末条件を満たさない特権ログイン、機密ラベル付きファイルの大量参照——この3つを同時に要求しているためです。これが「CVSSの高い順に並べない」という設計判断の実測的な裏付けです。

### 閾値を上げても解決しません

大量参照の閾値と時間窓をスイープした結果（抜粋、全21通りは `evaluation/synthetic-baseline.md`）。

| 異なるファイル数 | 時間窓(秒) | AS-003 検知 | AS-003 誤検知 | 検知漏れ | 誤検知/日 |
|---|---|---|---|---|---|
| 60 | 300 | 1 | 115 | 0 | 6.58 |
| 100 | 300 | 1 | 102 | 0 | 5.89 |
| 150 | 300 | 0 | 77 | 2 | 4.56 |
| 300 | 120 | 0 | 0 | 2 | 0.48 |
| 800 | 300 | 0 | 0 | 2 | 0.48 |

誤検知が0になる設定では、ラベル付き事案（130ファイル / 約4.5分）も検知できなくなります。**単体ルールの閾値調整では、静かさと検知を同時に満たせません。** 探索範囲で検知漏れ0を保てるのは既定値の 100 / 300 でした。

### AS-002 は条件の組み合わせを変えると静かになります

既定の `identity_conditions: "any"` は「非管理端末 **または** 未承認」で検知します。承認済みの作業でも私物端末なら該当するため、正常な保守接続が9件の誤検知になりました。

```json
{ "identity_conditions": "both" }
```

「非管理端末 **かつ** 未承認」に変えた場合:

| ルール | 件数 | 検知 | 誤検知 |
|---|---|---|---|
| AS-002 | 1 | 1 | 0 |
| AS-003 | 103 | 1 | 102 |
| AS-004 | 1 | 1 | 0 |

事案は引き続き検知でき、誤検知は111→102件（1日あたり5.89→5.41件）に減りました。ただし、**承認済みだが非管理端末からの特権接続を見逃す** ことになります。どちらが妥当かは、組織のBYOD方針しだいです。これは製品が決める話ではありません。

## 設定項目

| 項目 | 既定値 | 意味 |
|---|---|---|
| `window_seconds` | 300 | 大量参照を数える時間窓（秒） |
| `distinct_file_threshold` | 100 | 窓内で検知に必要な異なるファイル数 |
| `login_lookback_seconds` | 1800 | 大量参照の直前ログインを関連付ける上限（秒） |
| `sensitive_file_minimum` | 1 | 相関に必要な機密ラベル付きファイル数 |
| `stale_asset_hours` | 24 | 資産情報を古いと判定する経過時間 |
| `cvss_priority_threshold` | 7.0 | 公開状況が不明な資産をP2に上げるCVSS下限 |
| `identity_conditions` | `any` | 特権ログインの検知条件。`any` / `both` |

未定義の項目、範囲外の値、真偽値と整数の取り違えは拒否します。値を丸めて受け入れることはしません。設定はハッシュ化され、起動時に `rules.configured` として監査チェーンへ記録され、各検知結果にも `rule_config_digest` として付きます。誰がいつ感度を下げたかが後から分かるようにするためです。

## この測定でできていないこと

- 合成データは実組織のログではありません。ここでの誤検知率は**実環境の誤検知率ではありません**。
- 正常側に含めたのは、バックアップ、分析作業、移行作業、検索インデックス、週次ウイルススキャン、eDiscovery、バッチETL、承認済み保守です。実環境にはこれ以外の正常な大量参照もあります。ノイズを足すほど AS-003 の誤検知は増え、AS-004 は0のままでした。
- 事案側は1パターンだけです。低速な持ち出し、複数セッションへの分割、複数サーバーへの分散は、現在のルールでは検知できません。スイープはそれを測っていません。
- 検知までの時間、対応の所要時間、実際の被害低減は測定していません。
- 推奨値は、探索範囲で「検知漏れ0のうち誤検知が最少、同点なら最も感度の高い設定」を選ぶだけの単純な規則です。運用コストと見逃しリスクの重み付けは含みません。

## 次にやること

導入検討時にまず行うのは、機能追加ではなく次の3つです。

1. 対象企業の認証ログ・接続機器ログ・ファイル参照ログを、`aisecure import` で正しく読めるところまで持っていく（`docs/CONNECTORS.md` の品質レポートで確認）。
2. 事案が起きていない期間で測り、1日あたりの確認件数が運用可能かを見る。
3. その結果をもとに閾値と条件を決め、`--rules` として固定する。

ここを通過してから、承認付きの実対応（現在は未実装）へ進む構成です。
