docs: mise à jour README + RAPPORT_FINAL v2.0.0

- README: version 2.0.0, TCP fingerprinting, clustering multi-métriques,
  structure fichiers mise à jour, endpoints API complets, workflows
  d'investigation, services techniques, tables ClickHouse, thème

- RAPPORT_FINAL: section v2.0.0 avec détails TCP fingerprinting
  (20 signatures, scoring multi-signal, résultats production),
  clustering (21 features, K-means++, PCA, résultats 289 bots),
  redesign visualisation (tableau de bord + graphe), points d'attention

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
SOC Analyst
2026-03-19 08:54:06 +01:00
parent e2db8ca84e
commit 9de59f5681
2 changed files with 363 additions and 96 deletions

View File

@ -106,3 +106,137 @@
- Les **scores négatifs** dans `anomaly_score` et `worst_score` sont normaux — toujours utiliser `abs()` pour l'affichage
- Les **IPv6-mapped** (`::ffff:x.x.x.x`) sont présentes dans toutes les vues agrégées — systématiquement utiliser `replaceRegexpAll(toString(src_ip), '^::ffff:', '')`
---
# Rapport — v2.0.0 : TCP Fingerprinting Multi-Signal + Clustering IPs
**Date :** 2026-03-19
**Commit :** `e2db8ca`
---
## 1. TCP Fingerprinting OS amélioré
### Problème initial
L'ancien `tcp_spoofing.py` utilisait uniquement le TTL avec 3 plages grossières (≤64 = Linux, ≤128 = Windows, sinon = Network). Résultat : faux positifs, aucune détection de bots scanners.
### Solution implémentée
**`backend/services/tcp_fingerprint.py`** — 20 signatures OS, scoring multi-signal :
| Signal | Poids | Source ClickHouse |
|--------|-------|------------------|
| TTL initial (estimé) | 40% | `tcp_ttl_raw` |
| MSS | 30% | `tcp_mss_raw` |
| Fenêtre TCP | 20% | `tcp_win_raw` |
| Scale factor | 10% | `tcp_scale_raw` |
**Détections validées en production :**
- **Masscan** : `win=5808, mss=1452, scale=4, TTL 4857` → confiance **97%**
- **Googlebot** : stack Windows détecté avec UA Android → **spoof confirmé**
- **Bot-tool** : `risk_score += 30` (vs +15 pour spoof simple)
**MSS → chemin réseau :**
- 1460 → Ethernet standard
- 1452 → PPPoE / DSL (Masscan pattern)
- 14201452 → VPN probable
- < 1420 Tunnel / double-encapsulation
**Fichiers modifiés :**
- `backend/services/tcp_fingerprint.py` (nouveau)
- `backend/routes/tcp_spoofing.py` (réécriture complète queries `agg_host_ip_ja4_1h`)
- `backend/routes/investigation_summary.py` (utilise le service tcp_fingerprint)
- `frontend/src/components/TcpSpoofingView.tsx` (nouvelles colonnes MSS/scale/confiance, graphique distribution MSS)
---
## 2. Clustering IPs multi-métriques
### Problème initial
La première version du clustering utilisait uniquement des règles sur les propriétés TCP. L'utilisateur a demandé d'utiliser **l'ensemble des métriques disponibles**.
### Solution implémentée
**`backend/services/clustering_engine.py`** K-means++ pur Python (sans dépendances ML) :
**21 features normalisées [0,1] :**
| Catégorie | Features |
|-----------|----------|
| Stack TCP (4) | TTL initial, MSS, scale, fenêtre |
| Anomalie ML (6) | score, vélocité, fuzzing, headless, POST ratio, IP-ID zéro |
| TLS/Protocole (5) | ALPN mismatch, ALPN absent, efficacité H2, ordre headers, UA-CH mismatch |
| Navigateur (1) | score navigateur moderne (normalisé /50) |
| Temporel (3) | entropie, diversité JA4 (log1p), UA rotatif |
| Comportement (2) | ratio assets, ratio accès direct |
**Algorithme :**
```
K-means++ : init O(k·n), n_init=3, meilleure inertie retenue
Power iter : X^T(Xv) trick, O(n·d) par iter — pas de matrice n×n
Déflation : Hotelling pour PC2 après extraction PC1
```
**Stratégie d'échantillonnage :** `ORDER BY avg(abs(anomaly_score)) DESC` les bots (score élevé) sont inclus en priorité, même si leurs hits individuels sont faibles (cas Masscan).
**Résultats en production (k=14, 3000 IPs) :**
- **289 bots confirmés** : clusters UA rotatif + UA-CH mismatch (cloud providers : Microsoft, Google, Akamai)
- **655 IPs suspects** : anomalie ML modérée ou UA-CH incohérent
- **ASN dominants** : MICROSOFT-CORP-MSN-AS-BLOCK, GOOGLE-CLOUD-PLATFORM, OVH, AMAZON
- **Temps de calcul** : ~59 secondes (Python pur, 3000 points × 21 features)
---
## 3. Visualisation clustering redesignée
### Problème initial
La première version utilisait des bulles ReactFlow positionnées par PCA. L'utilisateur a signalé : **"l'affichage du graphe est illisible"**.
### Solution implémentée
**Deux vues distinctes, accessibles par onglets :**
#### ⊞ Tableau de bord (défaut — toujours lisible)
- Grille de cartes groupées par niveau de risque
- **Bots & Menaces confirmées** (rouge) **Suspects** (orange) **Légitimes** (vert)
- Chaque carte : label + IP count + hits + badge CRITIQUE/ÉLEVÉ/MODÉRÉ/SAIN + 4 mini-barres + stack TCP + pays + ASN
#### ⬡ Graphe de relations
- Nœuds-cartes ReactFlow (220px texte entièrement lisible)
- **Colonnes par niveau de menace** (disposition déterministe, pas PCA)
- Arêtes colorées : orange=similaire, gris=distant, animé=très fort
- Légende intégrée, minimap, contrôles zoom
#### Sidebar de détail
- RadarChart comportemental (10 axes)
- Toutes les métriques avec barres de progression
- Liste des IPs avec badges menace/pays
- Export **Copier IPs** + ** CSV**
- Intégrée dans le flux flex (ne bloque plus la barre de contrôle)
**Fichiers modifiés :**
- `backend/routes/clustering.py` (réécriture complète)
- `backend/services/clustering_engine.py` (nouveau seuils calibrés sur données réelles)
- `frontend/src/components/ClusteringView.tsx` (réécriture complète)
- `frontend/src/App.tsx` (route `/clustering` + nav "🔬 Clustering IPs")
---
## 4. Points d'attention
### Performances
- K-means++ sur 3000 × 21 : **59s** (acceptable pas de cache implémenté)
- Le cache mémoire du drill-down (`_cache["cluster_ips"]`) est volatile : rechargement = recalcul
- Pour améliorer : cache Redis ou TTL 5 min avec `functools.lru_cache`
### Calibration des seuils
Les seuils de `name_cluster()` et `risk_score_from_centroid()` sont calibrés sur les données observées :
- `anomaly_score` en production : plage 0.20.35 (pas 01 comme attendu)
- Score normalisé affiché : `min(1, score / 0.5)` pour étirer la plage utile
- UA-CH mismatch = 1.0 sur les clusters bot = signal **très fort** (cloud providers simulant un navigateur)
### Données manquantes dans le LEFT JOIN
Certaines IPs n'apparaissent pas dans `ml_detected_anomalies` (score=0, fuzz=0). Ce sont les IPs légitimes non détectées par le modèle ML. Elles forment naturellement les clusters "Trafic Légitime".
### Fuzzing_index = 100% dans beaucoup de clusters
Après analyse : le `fuzzing_index` log-normalisé dépasse souvent le seuil de 100% car les valeurs brutes sont très variables (0 à 229+). Ce n'est pas un bug c'est la nature du trafic web moderne (beaucoup de requêtes avec des paths variés).