概要 — 何をする画面か
Security ▸ Detections(/security/detections)は InfraGuard の検知フラッグシップ画面です。3 つを 1 画面にまとめています。
- 検知アルゴリズムの解説 — 各エンジンがどのような原理で脅威を捕らえるかを教育用ポップオーバーで説明(Kitsune ML · srct ヒューリスティック · nginx
is_suspicious· JA3)。 - 検知後の物語 — 各検知エンジンが直近のウィンドウで捕らえた異常 IP · 不審な Web アクセス · run 履歴を実データで可視化。
- ★ JA3 シーケンス ルールセット — 単一送信元 IP の時系列 JA3 フィンガープリント列を決定的ヒューリスティックが読み取り、その「連続した異常行動」を専門用語のルールセット(
infr_sec_ruleset)として列挙・保存します。
収集と自動ブロックはすでにバックエンドで動いています(旧 stats-design の UI はファイアウォール・ブラックリストの表だけでした)。この画面の目的は、その隠れたテレメトリを信頼できる物語として表に出すことです。
この画面は読み取り中心 + オンデマンド分析です。検知エンジン自体(kts_tx・srct_tx・eve_ingest)は対象ホスト上で pm2 により動作する Node コレクターであり、アプリはそれらが埋めたテーブルを読むだけです。アプリ自身がトラフィックをスニッフィングすることはありません。
LLM によるナレーション経路は 2026-09-04 に削除されました。 以前はシーケンスの要約を AI アダプターに送り、その自由記述の回答を保存していました。実測で確認された 3 つの問題が理由です — LLM の結論(「JA3 ローテーション」)は比率計算 3 行がすでに出していたものと同じなのに 1 回あたり約 9,100 トークンを消費し、自由記述をそのまま保存するため書き手の言語が固定され英語セッションが韓国語のカードを読むことになり、フォールバック経路でも
provider/modelにアダプターの値を刻んでいたため保存済み 13 行のうち 10 行がmodel=kimi-k2.6と名乗りながら実際はテンプレート出力でした。現在はヒューリスティックのみが動作し、外部呼び出しもトークン費用もありません。provider/modelは実際に動いたものだけを記録します。
いつ使うか
- ある IP がボットネット / 自動化スキャナかどうかを JA3 ローテーションのパターンから判定したいとき。
- IDS・ML・nginx の各エンジンがいま何を捕らえているかを一目で確認するとき(トリアージの入口)。
- 検知コレクターを新しいホストに配備するとき(pm2 コマンド・ソースコードのコピー)。
- 上位 JA3 オフェンダーを分析してブロック / 通報の推奨ルールセットを作るとき。
- Overview · Threats からディープリンクで遷移し、特定の IP をすぐ分析するとき(
?ip=プリセレクト)。
画面構成
KPI ストリップ
| KPI | 意味 | 出典 |
|---|---|---|
| AI 異常 | 選択ウィンドウ内の Kitsune 異常検知件数 | kitsune_detail_log count |
| AI ブロック | そのうち is_blocked=1(しきい値 + veto を満たしたもの) |
kitsune_detail_log where is_blocked |
| 不審な Web アクセス | ウィンドウ内の nginx is_suspicious=1 リクエスト数 |
nginx_meta_ct count |
| ルールセット | 現在有効(status=active)なルールセット数 |
infr_sec_ruleset |
最初の 2 つの KPI が「AI」なのは、Kitsune が実際に機械学習のオートエンコーダだからです — このラベルは事実なのでそのまま残します。
検知アルゴリズム パネル(edu ポップオーバー)
各エンジンのカードから原理 · 何を見るか · tip を開く教育用ポップオーバー。文言は静的な security.det.edu.* lang パックが保持します。
- Kitsune — アンサンブル オートエンコーダによる異常検知
- srct — Suricata ヒューリスティック自動ブロッカー(5 カテゴリ)
- nginx is_suspicious — TLS 終端での Web 攻撃マーカー
- JA3 シーケンス分析 — この画面の主役
pm2 配備ガイド
検知コレクター 5 種を対象ホストに pm2 cron として配備するコマンドとソースコードを提供します(§データソース · pm2 表)。
検知ログと run 履歴
- 異常 IP(Kitsune top) —
anomaly_score降順の上位 50: IP・スコア・セッション数・ブロック有無・run_ts。 - 不審な Web アクセス(nginx top) —
is_suspiciousヒット上位 12: src_ip・hits・最終 ts。 - run 履歴 —
kitsune_process_log·srct_process_logの直近 30 件(スキャン / ブロック数・メッセージ)。
JA3 オフェンダーとルールセット
- オフェンダー一覧 — 固定 6 時間ウィンドウでの上位 12 JA3 オフェンダー:
ja3_variety・tls_conns・sni_variety・last_ts・国(geo)。自ネットワーク(登録インスタンス IP の /24)は除外されます。 - ルールセット表 — 保存されたルールセットの最新 60 件: エンティティ・行動・分類・深刻度・推奨・信頼度・出所。行ごとに有効化 / 保留 / 削除。
使い方
1) 検知状況を確認する
上部の**ウィンドウ切替(1h / 6h / 24h)**で観測ウィンドウを変更します(既定 24h)。KPI と検知ログがそのウィンドウで再計算されます。画面は約 30 秒ごとにポーリングし、サービス側は 30 秒キャッシュします。
オフェンダー一覧だけは、ウィンドウ設定に関わらず常に直近 6 時間です。JA3 ローテーションは数時間かけて蓄積するため、短いウィンドウではパターンが現れません(自動ブロックの 360 分 JA3 ウィンドウと整合)。
2) JA3 シーケンス分析を実行する(★)
- オフェンダー一覧から IP を選ぶ(または Overview・Threats からのディープリンク)か、**[分析]**をクリックします。
- サーバーが
suricata_tls_ctからその IP の TLS JA3 シーケンスを時系列で取得します(ウィンドウ = 運用ポリシーsec_ai_window_min、既定 60 分 · 最大 200 行)。 - シーケンス長が最小値(
sec_ai_min_seq、既定 5)未満ならinsufficient_sequenceとしてスキップされます。 - ヒューリスティックがシーケンスを findings に分類します(下の規則表)。
- 結果がルールセットとして保存され、一覧と Overview のファネルが即座に更新されます。
レスポンス例:
{
"ok": true,
"provider": "heuristic",
"model": null,
"saved": 1,
"seq_len": 37,
"findings": [
{ "key": "ja3_rotation",
"params": { "conns": 37, "variety": 34 },
"category": "tls_anomaly",
"severity": "crit", "action": "block", "confidence": 91 }
]
}
分析は決定的かつ無料です — 同じシーケンスからは常に同じルールセットが得られ、外部サービスを呼ばず、ネットワークがなくても動作します。実行コストがないので、オフェンダーの数値が変わったら気軽に再分析してください。
ヒューリスティック規則
findings はシーケンス統計から組み立てます(rotation = ja3_variety / seq_len)。
| 条件 | ルールセット | 分類 | 深刻度 | 推奨 | 信頼度 |
|---|---|---|---|---|---|
| variety ≥ 3 かつ rotation ≥ 0.5 | JA3 ローテーション(自動化スキャナ / ボットネット) | tls_anomaly | rotation≥0.9 → crit、それ以外 warn | block | 50 + round(rotation×45)、最大 95 |
| 機密 URL を観測(.env・.git・wp-config…) | 認証情報 / 設定ファイルの探索 | credential_access | crit | block | 88 |
| variety = 1 かつ conns ≥ 10 かつ sni_variety ≥ 4 | 単一 JA3 による多標的スキャン | scan | warn | observe | 72 |
| 上記のいずれでもない | TLS ベースライン活動 | other | info | observe | 40 |
機密 URL は正規表現 .env .git wp-config .aws /actuator phpunit /.. shell.php wp-login xmlrpc でマッチします(nginx is_suspicious + suricata_http コンテキスト)。
分類・深刻度・推奨は挿入前にカラムの enum で検証されます(recon · credential_access · exfil · bruteforce · c2 · tls_anomaly · scan · other / info · warn · crit / observe · block · isolate · report)。
ルールセットの文言と言語
finding は文ではなく識別子として保存されます。heuristicFindings() は {key, params} を返し、行は rule_key + params(マイグレーション 000783)を保持します。文言は行を読む時点で、読み手の言語で適用されます。
- 文言は
resources/lang/<locale>/security.phpのdet.rule.<key>.{name,behavior}が保持し、コンソールの 8 言語すべてに翻訳されています。 name/behaviorカラムには引き続き英語のレンダリングがフォールバックとして入ります — エクスポート・監査、そして 000783 以前に書かれた行が読めなくなってはいけないためです。rule_keyが無い場合やそのロケールにキーが無い場合は保存されたテキストを使い、生のキーが表示されることはありません。- Detections のキャッシュはロケール別です(
infr:sec:det:<locale>:<range>)。これが無いと、韓国語セッションが温めた 30 秒キャッシュを次の英語の読者がそのまま受け取ります — 実際にそうなっていました。
000783 より前に作られた行は元のテキストを保持します。マイグレーションは、その行自身の evidence から旧テンプレートを再構成して完全一致した場合にのみ
rule_keyを復元します(推測はしません)。旧 LLM 経路が書いた自由記述の行は、その IP を再分析して置き換えられるまでそのまま残ります。
3) ルールセットを管理する
| アクション | 効果 |
|---|---|
| 有効化 | status=active(Overview のファネル / ブロックの物語に反映) |
| 保留 | status=dismissed |
| 削除 | 行を削除 |
再分析はその IP の既存の機械由来ルールセットのみを置き換えます(entity_type=ip, entity_key=ip, source=ai を削除して再作成) — 手作業で書いたルールセットは保持されます。
ルールセットの
actionフィールドは推奨であって命令ではありません。これに従って動作するコードはありません — 自動ブロックはsuricata_tls_ctから JA3 ローテーションを直接計算し、infr_sec_rulesetを読みません。action=blockのルールセットがあっても何もブロックされません。ブロックは Blocklist から行うか、自動ブロックのスケジューラが実行します。
4) スケジュールによる蓄積(オプトイン)
infr:sec-analyze コマンドが上位 JA3 オフェンダーを巡回してルールセットを蓄積します。単発実行して終了するコマンドなので、スケジュールに安全に登録できます(デーモンではありません)。
# ゲートを無視して 1 回実行(デバッグ)
php artisan infr:sec-analyze --force
# 単一 IP を分析(ゲート無関係)
php artisan infr:sec-analyze --ip=203.0.113.10
- ゲート: 運用ポリシー
sec_ai_schedule_on(既定0= オフ)。オフのときは no-op です — 運用ポリシーのセキュリティタブで有効にします。 - スケジュール実行では上位
sec_ai_top_n(既定 10)のオフェンダーを分析します。 - スケジュールは 30 分ごとに動きますが、分析はヒューリスティックなのでトークン費用も外部呼び出しもありません。それでも既定がオフなのは、ルールセットが情報提供用だからです。
5) pm2 配備コマンドをコピーする
pm2 カードは**[コマンドをコピー](pm2 実行行)、[ソースをコピー](スニペット本体)、[インスタンス値を埋めてコピー]**(HOSTNAME/IP トークン置換)を提供します。ソースはシードされた Inventory ▸ Tools のスニペット(infr_snippet)から取得します。
データソース
読み取るレガシーテーブル(変更禁止)
| テーブル | 用途 | 供給コレクター |
|---|---|---|
kitsune_detail_log |
異常 IP・anomaly_score・is_blocked | kts_tx |
kitsune_process_log |
Kitsune の run 履歴 | kts_tx |
srct_process_log |
srct の run 履歴 | srct_tx |
nginx_meta_ct |
不審な Web リクエスト(is_suspicious) |
nginx_shipper/aggregator |
suricata_tls_ct |
JA3 シーケンス(ja3_hash・sni・version) | eve_ingest |
suricata_http_ct |
分析用の HTTP コンテキスト | eve_ingest |
blacklist_info |
自動ブロック結果(参照) | kts_tx · srct_tx |
ip_info_loop |
geo/ASN エンリッチメント | — |
アプリ所有の新規テーブル
infr_sec_ruleset(マイグレーション 000730 · 000783) — ルールセット。カラム:entity_type・entity_key・name・behavior・rule_key・params(json)・category・severity・action・confidence・ja3・sequence(json)・evidence(json)・source(ai=機械由来 | manual)・provider・model・status(draft|active|dismissed)。SecurityAiService::persist()が埋めます。infr_snippet— pm2 のソースコード本体。infr_audit_log—sec.ai_analyze・sec.ruleset_save・sec.ruleset_deleteを監査。最初のアクション文字列はそのまま残しています — 変更すると既存の監査証跡が 2 つに分かれてしまうためです。
pm2 配備コレクター
| key | 供給先 | 配備コマンド(cron-restart) |
|---|---|---|
| eve_ingest | suricata_*_ct |
pm2 start infr_eve_ingest.cjs --name infr-eve --cron-restart="0 0 * * 6" |
| kts_tx | kitsune_*_log · blacklist_info |
pm2 start infr_kts_tx.cjs --name infr-kitsune --cron-restart="0 0 * * 2" |
| srct_tx | srct_process_log · blacklist_info |
pm2 start infr_srct_tx.cjs --name infr-srct --cron-restart="0 0 * * 4" |
| sync_black | ipset · iptables |
pm2 start infr_sync_black.mjs --name infr-syncblack --cron-restart="*/5 * * * *" |
| sync_firewall | firewall_status |
pm2 start infr_sync_firewall.cjs --name infr-firewall --cron-restart="0 0 * * 0" |
サービスとルート
- DetectionService — KPI・検知ログ・オフェンダー・ルールセットを構築(ロケール別の 30 秒キャッシュ、
SecurityRepository経由の読み取り専用)。phrase()が読み取り時にルールセットの文言を適用します。 - SecurityAiService — JA3 シーケンス → ヒューリスティック findings → ルールセット upsert。LLM 呼び出しは含みません。
- SecurityScope::excludePrefixes() — 自ネットワークの除外(登録インスタンス IP の /24 + 運用ポリシー · ハードコーディング禁止)。
| メソッド | ルート |
|---|---|
| GET | /security/detections(index) |
| GET | /security/detections/live(ポーリング) |
| POST | /security/detections/analyze(分析) |
| POST | /security/detections/ruleset/save |
| POST | /security/detections/ruleset/delete |
アクセス権限
| 操作 | ゲート |
|---|---|
| 画面の閲覧 | Security ロール領域へのアクセス(min_req 2) — demo(1)はセキュリティ領域自体が見えず、staff(5)・admin(10)は閲覧可能 |
| 分析 / ルールセットの保存・削除 | user_level ≥ 2(canWrite)+ infr_audit_log 監査 |
- 書き込みゲートはコントローラーの
canWrite()(セッションinfr_user_level ≥ 2)で強制されます — demo レベルは分析もルールセット編集もできません。 - IP 入力は
filter_var(FILTER_VALIDATE_IP)で検証します(不正な IP → 422)。 - すべての破壊的操作は監査ログに記録されます → 監査。
トラブルシューティング & FAQ
分析が
insufficient_sequenceでスキップされる — その IP のsuricata_tls_ctシーケンスがsec_ai_min_seq(既定 5)未満です。ウィンドウ(sec_ai_window_min、既定 60 分)を広げるか、オフェンダー一覧(6 時間ウィンドウ)からより活発な IP を選んでください。
- 古いルールセットが違う言語で表示される — 000783 より前に書かれ、テキストが固定された行です。その IP を再分析すれば、新しい行が
rule_keyを保存し読み手の言語に従います。もう現れない IP の行は表から削除できます。 - KPI やルールセットが変わらない — 30 秒キャッシュ + ポーリング周期のためです。分析とルールセット保存はキャッシュを即座に無効化するので(
flush· 全ロケールの変種)、再読み込みすれば反映されます。 - オフェンダー一覧が空 — 直近 6 時間の
suricata_tls_ctに JA3 の活動が無いか、すべて自ネットワークとして除外されました。eve_ingestコレクターが動いているか確認してください。 - スケジュールが何もしない —
sec_ai_schedule_on=0(既定)です。運用ポリシーのセキュリティタブで有効にするか、--forceで 1 回実行してください。 - 検知ログがすべて 0 — 該当する pm2 プロセスが停止している可能性があります。pm2 カードの配備コマンドで再起動し、run 履歴を確認してください。
関連
