diff --git a/RAPPORT_FINAL.md b/RAPPORT_FINAL.md index 74e3f87..33297dc 100644 --- a/RAPPORT_FINAL.md +++ b/RAPPORT_FINAL.md @@ -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 48–57` → 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) +- 1420–1452 → 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** : ~5–9 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 : **5–9s** (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.2–0.35 (pas 0–1 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). diff --git a/README.md b/README.md index 8c5e617..7648988 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ Dashboard web interactif pour visualiser et investiguer les décisions de classification du Bot Detector IA. -**Version:** 1.7.0 - Subnet Investigation + IP Reputation +**Version:** 2.0.0 - TCP Fingerprinting Multi-Signal + Clustering IPs Multi-Métriques ## 🚀 Démarrage Rapide @@ -51,39 +51,63 @@ docker compose logs -f dashboard_web ### Dashboard Principal - **Métriques en temps réel** : Total détections, menaces, bots connus, IPs uniques +- **Comparaison baseline J-1** : variation ▲▼ vs hier (détections, IPs uniques, CRITICAL) - **Répartition par menace** : Visualisation CRITICAL/HIGH/MEDIUM/LOW - **Évolution temporelle** : Graphique des détections sur 24h - **Incidents clusterisés** : Regroupement automatique par subnet /24 - **Top Menaces Actives** : Top 10 des IPs les plus dangereuses -### Investigation Subnet /24 (NOUVEAU) -- **URL:** `/entities/subnet/x.x.x.x_24` (ex: `/entities/subnet/141.98.11.0_24`) -- **Stats globales** : Total IPs, détections, JA4 uniques, User-Agents uniques, Hosts -- **Tableau des IPs** : Toutes les IPs du subnet avec leurs statistiques -- **Actions par IP** : Investiguer, Voir détails -- **Sources** : `ml_detected_anomalies` (détections) + `view_dashboard_entities` (user-agents) +### 🧬 TCP Spoofing & Fingerprinting OS (amélioré v2.0) +- **Détection multi-signal** : TTL initial + MSS + scale + fenêtre TCP (p0f-style) +- **20 signatures OS** : Linux, Windows, macOS, Android, iOS, Masscan, ZMap, Shodan, Googlebot… +- **Estimation hop-count** : différence TTL initial (arrondi) − TTL observé +- **Détection réseau** : MSS → Ethernet (1460) / PPPoE (1452) / VPN (1420) / Tunnel (<1420) +- **Confiance 0–100%** : score pondéré (TTL 40% + MSS 30% + fenêtre 20% + scale 10%) +- **Badge bot-tool** : Masscan détecté à 97% (win=5808, mss=1452, scale=4) +- **Distribution MSS** : histogramme des MSS observés par cluster -### Investigation IP + Réputation (NOUVEAU) +### 🔬 Clustering IPs Multi-Métriques (nouveau v2.0) +- **URL:** `/clustering` +- **Algorithme :** K-means++ (Arthur & Vassilvitskii, 2007), initialisé avec k-means++, 3 runs +- **21 features normalisées [0,1] :** + - Stack TCP : TTL initial, MSS, scale, fenêtre TCP + - Anomalie ML : score, vélocité, fuzzing, headless, POST ratio, IP-ID zéro + - TLS/Protocole : ALPN mismatch, ALPN absent, efficacité H2 (multiplexing) + - Navigateur : score navigateur moderne, ordre headers, UA-CH mismatch + - Temporel : entropie, diversité JA4, UA rotatif +- **Positionnement 2D :** PCA par puissance itérative (Hotelling) + déflation +- **Nommage automatique :** Masscan / Bot UA Rotatif / Bot Fuzzer / Anomalie ML / Linux / Windows / VPN + +**Vue Tableau de bord (défaut) :** + - Grille de cartes groupées : Bots confirmés → Suspects → Légitimes + - Chaque carte : label, IP count, hits, badge CRITIQUE/ÉLEVÉ/MODÉRÉ/SAIN + - 4 mini-barres : anomalie, UA-CH mismatch, fuzzing, UA rotatif + - Stack TCP (TTL, MSS, Scale), top pays, ASN + +**Vue Graphe de relations :** + - Nœuds-cartes ReactFlow (220px, texte lisible) + - Colonnes par niveau de menace : Bots | Suspects | Légitimes + - Arêtes colorées par similarité (orange=fort, animé=très fort) + - Légende intégrée, minimap, contrôles zoom + +**Sidebar de détail :** + - RadarChart comportemental (10 axes : anomalie, UA-CH, fuzzing, headless…) + - Toutes les métriques avec barres de progression colorées + - Liste des IPs avec badges menace/pays/ASN + - Export **Copier IPs** + **⬇ CSV** + +### Investigation Subnet /24 +- **URL:** `/entities/subnet/x.x.x.x_24` +- Stats globales, tableau des IPs, actions par IP + +### Investigation IP + Réputation - **URL:** `/investigation/:ip` -- **Panel Réputation IP** : - - Score de menace 0-100 - - Niveau: clean/low/medium/high/critical - - Détection: Proxy, Hosting, VPN, Tor - - Géolocalisation: Pays, Ville - - ASN + Organisation -- **Sources** : IP-API.com + IPinfo.io (sans clé API) +- Synthèse multi-sources (ML + bruteforce + TCP + JA4 + timeline) +- Score de risque 0–100, réputation IP-API + IPinfo ### Investigation (Variabilité) -- **Vue détails** : Cliquez sur une IP/JA4/pays/ASN pour investiguer -- **Variabilité des attributs** : - - User-Agents associés (avec pourcentages) - - JA4 fingerprints - - Pays de provenance - - ASN - - Hosts contactés - - Niveaux de menace -- **Insights automatiques** : Détection de comportements suspects -- **Navigation enchaînable** : Cliquez sur un attribut pour creuser +- User-Agents, JA4 fingerprints, pays, ASN, hosts, niveaux de menace +- Insights automatiques, navigation enchaînable ## 🏗️ Architecture @@ -92,51 +116,67 @@ docker compose logs -f dashboard_web │ Docker Compose │ │ ┌─────────────┐ ┌─────────────┐ ┌─────────────────┐ │ │ │ ClickHouse │ │ bot_detector│ │ dashboard_web │ │ -│ │ :8123 │ │ (existant) │ │ :3000 (web) │ │ -│ │ :9000 │ │ │ │ :8000 (API) │ │ +│ │ :8123 │ │ (existant) │ │ :8000 (web+API)│ │ +│ │ :9000 │ │ │ │ network=host │ │ │ └──────┬──────┘ └──────┬──────┘ └────────┬────────┘ │ │ └────────────────┴───────────────────┘ │ └─────────────────────────────────────────────────────────┘ ``` +> Le container utilise `network_mode: "host"` — le frontend buildé est servi par FastAPI +> sur le **port 8000 uniquement** (pas de port 3000 en production). + ### Composants -| Composant | Technologie | Port | Description | -|-----------|-------------|------|-------------| -| **Frontend** | React + TypeScript + Tailwind | 3000 | Interface utilisateur | -| **Backend API** | FastAPI (Python) | 8000 | API REST | -| **Database** | ClickHouse (existant) | 8123 | Base de données | +| Composant | Technologie | Description | +|-----------|-------------|-------------| +| **Frontend** | React 18 + TypeScript 5 + Vite 5 + Tailwind CSS 3 | Interface utilisateur (SPA) | +| **Backend API** | FastAPI 0.111 + Python 3.11 | API REST + serveur statique SPA | +| **Database** | ClickHouse (existant) — port 8123 | Base de données principale | +| **Clustering** | K-means++ pur Python + PCA puissance itérative | Algorithmes embarqués, sans dépendance ML | ## 📁 Structure ``` dashboard/ -├── Dockerfile # Image Docker multi-stage -├── requirements.txt # Dépendances Python +├── Dockerfile # Multi-stage: node:20-alpine → python:3.11-slim +├── docker-compose.yaml +├── requirements.txt ├── backend/ -│ ├── main.py # Application FastAPI -│ ├── config.py # Configuration -│ ├── database.py # Connexion ClickHouse -│ ├── models.py # Modèles Pydantic -│ └── routes/ -│ ├── metrics.py # Endpoint /api/metrics -│ ├── detections.py # Endpoint /api/detections -│ ├── variability.py # Endpoint /api/variability -│ └── attributes.py # Endpoint /api/attributes +│ ├── main.py # FastAPI: CORS, routers, SPA catch-all (doit être DERNIER) +│ ├── config.py # pydantic-settings, lit .env +│ ├── database.py # ClickHouseClient singleton (db) +│ ├── models.py # Modèles Pydantic v2 +│ ├── routes/ +│ │ ├── metrics.py # GET /api/metrics, /api/metrics/baseline +│ │ ├── detections.py # GET /api/detections +│ │ ├── variability.py # GET /api/variability +│ │ ├── attributes.py # GET /api/attributes +│ │ ├── incidents.py # GET /api/incidents/clusters +│ │ ├── entities.py # GET /api/entities +│ │ ├── analysis.py # GET/POST /api/analysis — classifications SOC +│ │ ├── reputation.py # GET /api/reputation/ip/{ip} +│ │ ├── tcp_spoofing.py # GET /api/tcp-spoofing — fingerprinting OS multi-signal +│ │ ├── clustering.py # GET /api/clustering/clusters + /cluster/{id}/ips +│ │ └── investigation_summary.py # GET /api/investigation/{ip}/summary +│ └── services/ +│ ├── tcp_fingerprint.py # 20 signatures OS, scoring, hop-count, réseau path +│ ├── clustering_engine.py # K-means++, PCA-2D, nommage, score risque (pur Python) +│ └── reputation_ip.py # httpx → ip-api.com + ipinfo.io (async, sans API key) └── frontend/ - ├── package.json # Dépendances Node - ├── src/ - │ ├── App.tsx # Composant principal - │ ├── components/ - │ │ ├── DetectionsList.tsx - │ │ ├── DetailsView.tsx - │ │ └── VariabilityPanel.tsx - │ ├── hooks/ - │ │ ├── useMetrics.ts - │ │ ├── useDetections.ts - │ │ └── useVariability.ts - │ └── api/ - │ └── client.ts # Client API + ├── package.json + ├── vite.config.ts # Proxy /api → :8000 en dev + └── src/ + ├── App.tsx # BrowserRouter + Sidebar + TopHeader + Routes + ├── ThemeContext.tsx # dark/light/auto, localStorage: soc_theme + ├── api/client.ts # Axios baseURL=/api + toutes les interfaces TypeScript + ├── components/ + │ ├── ClusteringView.tsx # K-means++ clustering — 2 vues + │ ├── TcpSpoofingView.tsx # TCP fingerprinting OS + │ ├── InvestigationView.tsx # Investigation IP complète + │ └── ... # Autres vues + ├── hooks/ # useMetrics, useDetections, useVariability (polling) + └── utils/STIXExporter.ts ``` ## 🔌 API @@ -146,46 +186,51 @@ dashboard/ | Method | Endpoint | Description | |--------|----------|-------------| | GET | `/api/metrics` | Métriques globales | +| GET | `/api/metrics/baseline` | Comparaison J-1 (détections, IPs, CRITICAL) | | GET | `/api/metrics/threats` | Distribution par menace | -| GET | `/api/detections` | Liste des détections | +| GET | `/api/detections` | Liste des détections paginée | | GET | `/api/detections/{id}` | Détails d'une détection | | GET | `/api/variability/{type}/{value}` | Variabilité d'un attribut | -| GET | `/api/attributes/{type}` | Liste des valeurs uniques | +| GET | `/api/attributes/{type}` | Valeurs uniques d'un attribut | | GET | `/api/incidents/clusters` | Incidents clusterisés par subnet /24 | -| GET | `/api/entities/subnet/{subnet}` | Investigation subnet (ex: `141.98.11.0/24`) | -| GET | `/api/entities/{type}/{value}` | Investigation entité (IP, JA4, UA, etc.) | +| GET | `/api/entities/subnet/{subnet}` | Investigation subnet (ex: `141.98.11.0_24`) | +| GET | `/api/entities/{type}/{value}` | Investigation entité (IP, JA4, UA…) | | GET | `/api/reputation/ip/{ip}` | Réputation IP (IP-API + IPinfo) | +| GET | `/api/investigation/{ip}/summary` | Synthèse IP multi-sources (ML + TCP + JA4) | | GET | `/api/analysis/{ip}/subnet` | Analyse subnet / ASN | -| GET | `/api/analysis/{ip}/country` | Analyse pays | -| GET | `/api/analysis/{ip}/ja4` | Analyse JA4 | -| GET | `/api/analysis/{ip}/user-agents` | Analyse User-Agents | | GET | `/api/analysis/{ip}/recommendation` | Recommandation de classification | | POST | `/api/analysis/classifications` | Sauvegarder classification SOC | +| GET | `/api/tcp-spoofing/overview` | Vue d'ensemble TCP spoofing + OS | +| GET | `/api/tcp-spoofing/list` | Liste des détections TCP spoofing | +| GET | `/api/tcp-spoofing/matrix` | Matrice OS déclaré vs OS réel | +| GET | `/api/clustering/clusters` | Clustering K-means++ (`?k=14&n_samples=3000`) | +| GET | `/api/clustering/cluster/{id}/ips` | IPs d'un cluster (drill-down) | | GET | `/health` | Health check | ### Exemples ```bash -# Métriques globales -curl http://localhost:3000/api/metrics +# Health check +curl http://localhost:8000/health -# Détections avec filtres -curl "http://localhost:3000/api/detections?threat_level=CRITICAL&page=1" +# Métriques globales + baseline +curl http://localhost:8000/api/metrics | jq '.summary' +curl http://localhost:8000/api/metrics/baseline | jq -# Variabilité d'une IP -curl http://localhost:3000/api/variability/ip/192.168.1.100 +# Détections CRITICAL +curl "http://localhost:8000/api/detections?threat_level=CRITICAL&page=1" | jq '.items | length' -# Investigation subnet (URL encode / en _24) -curl "http://localhost:3000/api/entities/subnet/141.98.11.0_24?hours=24" +# TCP Spoofing — vue d'ensemble +curl http://localhost:8000/api/tcp-spoofing/overview | jq + +# Clustering IPs (14 clusters sur 3000 échantillons) +curl "http://localhost:8000/api/clustering/clusters?k=14&n_samples=3000" | jq '.stats' + +# Drill-down d'un cluster +curl "http://localhost:8000/api/clustering/cluster/c0_k14/ips?limit=20" | jq '.ips[].ip' # Réputation IP -curl http://localhost:3000/api/reputation/ip/141.98.11.209 - -# Incidents clusterisés -curl http://localhost:3000/api/incidents/clusters?limit=20 - -# Liste des pays -curl http://localhost:3000/api/attributes/country +curl http://localhost:8000/api/reputation/ip/162.55.94.175 | jq ``` ## ⚙️ Configuration @@ -195,39 +240,127 @@ curl http://localhost:3000/api/attributes/country | Variable | Défaut | Description | |----------|--------|-------------| | `CLICKHOUSE_HOST` | `clickhouse` | Hôte ClickHouse | +| `CLICKHOUSE_PORT` | `8123` | Port HTTP ClickHouse | | `CLICKHOUSE_DB` | `mabase_prod` | Base de données | | `CLICKHOUSE_USER` | `admin` | Utilisateur | | `CLICKHOUSE_PASSWORD` | `` | Mot de passe | -| `API_PORT` | `8000` | Port de l'API | +| `API_HOST` | `0.0.0.0` | Bind Uvicorn | +| `API_PORT` | `8000` | Port API + frontend | +| `CORS_ORIGINS` | `["http://localhost:3000", ...]` | Origines CORS autorisées | Ces variables sont lues depuis le fichier `.env` à la racine du projet. +> ⚠️ Le fichier `.env` contient les credentials réels — ne jamais le committer. + ## 🔍 Workflows d'Investigation -### Exemple 1: Investiguer une IP suspecte +### Exemple 1 : Identifier un bot Masscan -1. **Dashboard** → Voir une IP classifiée 🔴 CRITICAL -2. **Clic sur l'IP** → Ouvre la vue détails -3. **Observer User-Agents** → 3 UA différents détectés -4. **Clic sur "python-requests"** → Voir toutes les IPs avec cet UA -5. **Découvrir 12 IPs** → Possible botnet -6. **Action** → Noter pour blacklist +1. **🔬 Clustering IPs** → Cluster "🤖 Masscan / Scanner IP" visible en rouge +2. **Clic sur la carte** → Sidebar : TTL=52, MSS=1452, Scale=4 — pattern Masscan +3. **Copier les IPs** → Liste prête pour le blocage +4. **Export CSV** → Import dans le SIEM ou firewall -### Exemple 2: Analyser un ASN +### Exemple 2 : Analyser des bots UA-rotatifs (cloud) -1. **Filtre** → ASN: OVH (AS16276) -2. **Voir 523 détections** → Beaucoup d'activité -3. **Variabilité** → 89 IPs différentes, 15 pays -4. **Insight** → "ASN de type hosting → Souvent utilisé pour des bots" -5. **Conclusion** → Activité normale pour un hébergeur +1. **Clustering** → Cluster "🤖 Bot UA Rotatif + CH Mismatch" (risque 50%) +2. **RadarChart** → UA-CH=100%, UA rotatif=100%, anomalie=59% +3. **Top ASN** → Microsoft, Google, Akamai — cloud providers +4. **🧬 TCP Spoofing** → Confirmer : ces IPs déclarent Windows UA mais ont TTL Linux +5. **Investigation IP** → Détail complet avec timeline 24h + +### Exemple 3 : Détecter le spoofing d'OS + +1. **🧬 TCP Spoofing** → Liste des IPs avec mismatch OS +2. **Matrice UA×OS** → User-Agent Android mais stack TCP Windows = spoof +3. **Confiance 85%** → MSS=1460 (Ethernet), scale=7, TTL≈64 → Linux réel +4. **Action** → Classer comme bot avec IP proxy + +### Exemple 4 : Investiguer une IP suspecte + +1. **🎯 Détections** → IP classifiée 🔴 CRITICAL +2. **Clic sur l'IP** → Synthèse : ML + TCP + JA4 + bruteforce + timeline +3. **Score de risque** : 85/100 +4. **User-Agents** → 3 UA différents en 24h (rotation) +5. **TCP** → TTL initial 128 (Windows) mais UA Linux → spoof +6. **Action** → Blacklist immédiate + +## 🧬 Services techniques (v2.0) + +### `backend/services/tcp_fingerprint.py` + +Détection multi-signal de l'OS réel basée sur la stack TCP : + +```python +from backend.services.tcp_fingerprint import fingerprint_os, detect_spoof + +result = fingerprint_os(ttl=52, win=5808, scale=4, mss=1452) +# → OSFingerprint(os_family="Masscan/Scanner", confidence=0.97, is_bot_tool=True) + +spoof = detect_spoof(declared_ua="Chrome/Windows", fingerprint=result) +# → SpoofResult(is_spoof=True, reason="UA Windows mais stack Masscan", risk_score=30) +``` + +**Poids du scoring :** TTL initial 40% + MSS 30% + fenêtre 20% + scale 10% + +**Estimation hop-count :** +- TTL observé 52 → TTL initial arrondi = 64 → hops = 64 − 52 = **12** +- TTL observé 119 → TTL initial = 128 → hops = 9 + +**MSS → chemin réseau :** +| MSS | Réseau détecté | +|-----|---------------| +| 1460 | Ethernet standard | +| 1452 | PPPoE / DSL | +| 1420–1452 | VPN probable | +| < 1420 | Tunnel / double-encap | + +### `backend/services/clustering_engine.py` + +K-means++ + PCA-2D embarqués en pur Python (sans numpy/sklearn) : + +``` +K-means++ init : O(k·n) distances, n_init=3 runs → meilleure inertie +Power iteration : X^T(Xv) trick → O(n·d) par itération, pas de matrice n×n +Déflation Hotelling : retire PC1 de X avant de calculer PC2 +``` + +**21 features normalisées [0,1]** — voir `FEATURES` dans le fichier. + +**Nommage automatique** par priorité décroissante : +1. Pattern Masscan (mss 1440–1460, scale 3–5, TTL<60) +2. Fuzzing agressif (fuzzing_index normalisé > 0.35 ≈ valeur brute > 100) +3. UA rotatif + UA-CH mismatch simultanés +4. UA-CH mismatch seul > 80% +5. Score anomalie ML > 20% + signal comportemental +6. Classification réseau / OS par TTL/MSS + +## 🗄️ Tables ClickHouse utilisées + +| Table / Vue | Routes | +|---|---| +| `mabase_prod.ml_detected_anomalies` | metrics, detections, variability, analysis, clustering | +| `mabase_prod.agg_host_ip_ja4_1h` | tcp_spoofing, clustering, investigation_summary | +| `mabase_prod.view_dashboard_entities` | entities (UA, JA4, paths, query params) | +| `mabase_prod.classifications` | analysis (classifications SOC manuelles) | +| `mabase_prod.audit_logs` | audit (optionnel — silencieux si absent) | + +**Conventions SQL :** +- IPs stockées en IPv6-mappé : `replaceRegexpAll(toString(src_ip), '^::ffff:', '')` +- `anomaly_score` peut être négatif : toujours utiliser `abs()` +- `fuzzing_index` peut dépasser 200 : normaliser avec `log1p` +- `multiplexing_efficiency` peut dépasser 1 : normaliser avec `log1p` +- Paramètres SQL : syntaxe `%(name)s` (dict ClickHouse) +- **SPA catch-all DOIT être le dernier router dans `main.py`** ## 🎨 Thème -Le dashboard utilise un **thème sombre** optimisé pour la sécurité : +Le dashboard utilise un **thème sombre** optimisé SOC (dark par défaut, clair et auto disponibles) : -- **Background** : Slate 900/800/700 -- **Menaces** : Rouge (CRITICAL), Orange (HIGH), Jaune (MEDIUM), Vert (LOW) -- **Accents** : Blue (primaire), Emerald (succès) +- **Tokens CSS sémantiques** : `bg-background`, `bg-background-card`, `text-text-primary`, `text-text-secondary`… +- **Taxonomie menaces** : rouge CRITICAL / orange HIGH / jaune MEDIUM / vert LOW +- **Persistance** : `localStorage` clé `soc_theme` +- **Ne jamais utiliser** de classes Tailwind brutes (`slate-800`) — toujours les tokens sémantiques ## 📝 Logs