docs: mise à jour complète — 7/8 techniques, 85 features, 12 modules
Reflète l'état réel du système après les étapes 1-9 du roadmap : - §5.2 (fleet_detector NetworkX/Louvain) et §5.8 (Jaccard cross-domain) : ✅ - MetaLearner (régression logistique, fallback poids fixes) : documenté - ExIFFI (profondeur isolation EIF) + erreur AE par feature : documenté - KL divergence en complément du KS, drift adversarial : documenté - HTTP/2 fingerprinting (h2_fingerprint, dict_browser_h2, axis_h2_coherence) : documenté - Métriques de cycle (metrics.py, ml_performance_metrics, alertes) : documenté - Browser confidence : 5 axes → 6 axes (axis_h2_coherence) - 85 features (73 FEATURES + 12 FEATURES_COMPLET), 12 modules, 53 routes dashboard - Conformité thèse : 99.4% (était 97.9%), §5 : 87.5% (était 62.5%) - Tables nouvelles : fleet_detections, ml_performance_metrics, soc_feedback - Dictionnaires : 8 (dict_browser_h2 ajouté) - Dashboard : 16 pages + 37 API routes (fleet, health ajoutés) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
@ -3,14 +3,16 @@
|
||||
Service Python de détection d'anomalies par apprentissage automatique semi-supervisé
|
||||
sur le trafic HTTP/TLS agrégé dans ClickHouse. Fonctionne en cycle continu
|
||||
(par défaut toutes les 5 minutes) avec un **ensemble à triple voix**
|
||||
(Extended Isolation Forest + Autoencoder + XGBoost), enrichi par l'explicabilité
|
||||
SHAP, le clustering HDBSCAN et la détection multifactorielle des navigateurs.
|
||||
(Extended Isolation Forest + Autoencoder + XGBoost) piloté par un **méta-learner
|
||||
à régression logistique**, enrichi par l'explicabilité **ExIFFI** et **SHAP**,
|
||||
le clustering HDBSCAN, la détection de flottes coordonnées (NetworkX) et
|
||||
la surveillance de performance par cycle.
|
||||
|
||||
---
|
||||
|
||||
## Architecture des modules
|
||||
|
||||
Le service est découpé en **11 modules** organisés ainsi :
|
||||
Le service est découpé en **12 modules** organisés ainsi :
|
||||
|
||||
```
|
||||
__main__.py Point d'entrée (python -m bot_detector)
|
||||
@ -18,12 +20,14 @@ __main__.py Point d'entrée (python -m bot_detector)
|
||||
├─ config.py Variables d'environnement, flags de disponibilité
|
||||
├─ log.py Journalisation structurée JSON (structlog + RotatingFileHandler)
|
||||
├─ infra.py Client ClickHouse (via ja4_common), health check HTTP, arrêt propre
|
||||
├─ preprocessing.py Nettoyage du DataFrame, imputation, listes de features
|
||||
│ └─ browser.py Identification multifactorielle des navigateurs (5 axes)
|
||||
├─ pipeline.py Orchestration : filtrage → entraînement → scoring → fusion
|
||||
├─ preprocessing.py Nettoyage du DataFrame, imputation, listes de features (FEATURES, FEATURES_COMPLET)
|
||||
│ └─ browser.py Identification multifactorielle des navigateurs (6 axes)
|
||||
├─ pipeline.py Orchestration : filtrage → entraînement → MetaLearner → ExIFFI → scoring → fusion
|
||||
│ ├─ models.py EIF, TrafficAutoEncoder (PyTorch), XGBoost
|
||||
│ └─ scoring.py Normalisation, seuil adaptatif, SHAP, HDBSCAN, dérive
|
||||
└─ (insère dans ml_all_scores + ml_detected_anomalies)
|
||||
│ └─ scoring.py Normalisation, MetaLearner, seuil adaptatif, ExIFFI, SHAP, HDBSCAN, dérive KS+KL
|
||||
├─ fleet.py Graphe bipartite JA4×ASN (NetworkX), fleet_score, fleet_detections
|
||||
├─ metrics.py Métriques de cycle, alertes, ml_performance_metrics
|
||||
└─ (insère dans ml_all_scores + ml_detected_anomalies + fleet_detections + ml_performance_metrics)
|
||||
```
|
||||
|
||||
| Module | Lignes | Rôle |
|
||||
@ -31,14 +35,15 @@ __main__.py Point d'entrée (python -m bot_detector)
|
||||
| `config.py` | 154 | Toute la configuration via `os.getenv()`, flags de disponibilité des librairies |
|
||||
| `log.py` | 65 | `log_info()`, `log_decision()`, `append_training_history()` — JSONL rotatif |
|
||||
| `infra.py` | 89 | Client ClickHouse (délègue à `ja4_common`), `score_to_threat_level()`, serveur de santé en thread daemon |
|
||||
| `browser.py` | 170 | Détection multifactorielle des navigateurs sur 5 axes pondérés |
|
||||
| `scoring.py` | 279 | Normalisation, seuil adaptatif, SHAP top-3, HDBSCAN, détection de dérive |
|
||||
| `models.py` | 478 | `TrafficAutoEncoder`, entraînement/chargement EIF, XGBoost, élagage de features |
|
||||
| `preprocessing.py` | 117 | `preprocess_df()` — nettoyage, typage, imputation, listes `FEATURES` / `FEATURES_COMPLET` |
|
||||
| `pipeline.py` | 378 | `run_semi_supervised_logic()` — orchestration complète d'un modèle |
|
||||
| `cycle.py` | 371 | `fetch_and_analyze()` — boucle principale, feedback SOC, multiwindow |
|
||||
| `browser.py` | 191 | Détection multifactorielle des navigateurs sur **6 axes** pondérés (ajout `axis_h2_coherence`) |
|
||||
| `scoring.py` | 564 | `MetaLearner` (régression logistique), normalisation, seuil adaptatif, ExIFFI, SHAP top-5, HDBSCAN, dérive KS+KL |
|
||||
| `models.py` | 484 | `TrafficAutoEncoder`, entraînement/chargement EIF, XGBoost, élagage de features |
|
||||
| `preprocessing.py` | 127 | `preprocess_df()` — nettoyage, typage, imputation, listes `FEATURES` / `FEATURES_COMPLET` |
|
||||
| `pipeline.py` | 441 | `run_semi_supervised_logic()` — orchestration complète d'un modèle, MetaLearner, ExIFFI |
|
||||
| `fleet.py` | 174 | `build_fleet_graph()`, `detect_fleet_communities()`, `enrich_with_fleet_score()` — NetworkX + HDBSCAN |
|
||||
| `metrics.py` | 166 | `record_cycle_metrics()`, `_emit_alerts()` — table `ml_performance_metrics` |
|
||||
| `cycle.py` | 415 | `fetch_and_analyze()` — boucle principale, feedback SOC, multiwindow |
|
||||
| `__main__.py` | 41 | Point d'entrée, bannière de démarrage, boucle `while True` |
|
||||
| `__init__.py` | 1 | Docstring du package |
|
||||
|
||||
---
|
||||
|
||||
@ -171,8 +176,8 @@ Deux modèles indépendants tournent sur chaque cycle :
|
||||
|
||||
| Modèle | Condition | Features | Données |
|
||||
|--------|-----------|----------|---------|
|
||||
| **Complet** | `correlated = 1` | 77 (`FEATURES_COMPLET`) | HTTP + TCP + TLS (L3→L7) |
|
||||
| **Applicatif** | `correlated = 0` | 65 (`FEATURES`) | HTTP seul (L7 pur) |
|
||||
| **Complet** | `correlated = 1` | 85 (`FEATURES_COMPLET`) | HTTP + TCP + TLS (L3→L7) |
|
||||
| **Applicatif** | `correlated = 0` | 73 (`FEATURES`) | HTTP seul (L7 pur) |
|
||||
|
||||
En mode multi-fenêtre (`ENABLE_MULTIWINDOW=true`), deux variantes supplémentaires sont exécutées sur la vue 24h : `Complet_24h` et `Applicatif_24h`.
|
||||
|
||||
@ -320,7 +325,7 @@ Chaque anomalie reçoit un `campaign_id` (−1 = pas de cluster).
|
||||
|
||||
## Liste des features
|
||||
|
||||
### Features communes — modèle Applicatif (65 features)
|
||||
### Features communes — modèle Applicatif (73 features)
|
||||
|
||||
#### Comportement HTTP
|
||||
|
||||
@ -398,32 +403,51 @@ Chaque anomalie reçoit un `campaign_id` (−1 = pas de cluster).
|
||||
|---------|-------------|
|
||||
| `anubis_is_flagged` | Signal de suspicion Anubis (bot détecté, action ni ALLOW/DENY/vide) |
|
||||
|
||||
#### Navigateur multifactoriel
|
||||
#### Navigateur multifactoriel — 6 axes
|
||||
|
||||
| Feature | Description |
|
||||
|---------|-------------|
|
||||
| `is_known_browser` | JA4 correspond à un navigateur connu |
|
||||
| `browser_consistency_score` | Score composite de cohérence navigateur |
|
||||
| `browser_confidence` | Confiance globale de l'identification navigateur |
|
||||
| `axis_ja4_known` | Score de l'axe 1 (JA4 connu) |
|
||||
| `axis_ja4_struct` | Score de l'axe 2 (structure JA4) |
|
||||
| `axis_http_modern` | Score de l'axe 3 (HTTP moderne) |
|
||||
| `axis_nav_behavior` | Score de l'axe 4 (comportement navigation) |
|
||||
| `axis_tls_coherence` | Score de l'axe 5 (cohérence TLS/TCP) |
|
||||
| `browser_confidence` | Confiance globale de l'identification navigateur (seuil 0.55) |
|
||||
| `axis_ja4_known` | Axe 1 : JA4 reconnu dans `dict_browser_ja4` |
|
||||
| `axis_ja4_struct` | Axe 2 : structure JA4 cohérente (chiffrement, extensions TLS) |
|
||||
| `axis_http_modern` | Axe 3 : comportement HTTP moderne (Sec-Fetch-*, Accept-Language) |
|
||||
| `axis_nav_behavior` | Axe 4 : comportement de navigation (asset_ratio, referer, cascade) |
|
||||
| `axis_tls_coherence` | Axe 5 : cohérence TLS/TCP (ALPN, SNI, MSS mobile) |
|
||||
| `axis_h2_coherence` | Axe 6 : cohérence HTTP/2 (h2_fingerprint ↔ famille navigateur déclarée) |
|
||||
|
||||
#### Thèse §5 — Features avancées
|
||||
|
||||
| Feature | Description |
|
||||
|---------|-------------|
|
||||
| `path_transition_entropy` | Entropie des transitions de chemins |
|
||||
| `cadence_cv` | Coefficient de variation de la cadence de requêtes |
|
||||
| `burst_ratio` | Fraction de requêtes en rafale |
|
||||
| `pause_ratio` | Fraction de pauses longues |
|
||||
| `lag1_autocorrelation` | Autocorrélation lag-1 des inter-arrivées |
|
||||
| `path_transition_entropy` | Entropie des transitions de chemins (§5.1) |
|
||||
| `cadence_cv` | Coefficient de variation de la cadence de requêtes (§5.3) |
|
||||
| `burst_ratio` | Fraction de requêtes en rafale (§5.3) |
|
||||
| `pause_ratio` | Fraction de pauses longues (§5.3) |
|
||||
| `lag1_autocorrelation` | Autocorrélation lag-1 des inter-arrivées (§5.3) |
|
||||
| `benford_deviation` | Déviation par rapport à la loi de Benford |
|
||||
| `host_diversity` | Diversité des hôtes ciblés |
|
||||
| `host_sweep_speed` | Vitesse de balayage des hôtes |
|
||||
| `host_coverage_uniformity` | Uniformité de couverture des hôtes |
|
||||
| `root_to_first_asset_delay` | Délai HTML → premier asset (§5.4, détection headless) |
|
||||
| `asset_load_stddev` | Écart-type des intervalles de chargement d'assets (§5.4) |
|
||||
| `host_diversity` | Diversité des hôtes ciblés (§5.8) |
|
||||
| `host_sweep_speed` | Vitesse de balayage des hôtes (§5.8) |
|
||||
| `host_coverage_uniformity` | Uniformité de couverture des hôtes (§5.8) |
|
||||
| `cross_domain_path_similarity` | Similarité Jaccard inter-hôte des chemins — scanner latéral (§5.8) |
|
||||
|
||||
#### Features HTTP/2
|
||||
|
||||
| Feature | Description |
|
||||
|---------|-------------|
|
||||
| `h2_settings_known` | Fingerprint HTTP/2 reconnu dans `dict_browser_h2` (0/1) |
|
||||
| `h2_pseudo_order_match` | Ordre des pseudo-headers cohérent avec le navigateur déclaré (0/1) |
|
||||
| `h2_ja4_coherence` | Cohérence HTTP/2 ↔ JA4 (même famille) (0/1) |
|
||||
| `h2_settings_rare` | Fingerprint HTTP/2 avec <100 occurrences globales (0/1) |
|
||||
|
||||
#### Score de cohérence cross-layer
|
||||
|
||||
| Feature | Description |
|
||||
|---------|-------------|
|
||||
| `fingerprint_coherence_score` | Score composite (0.0–1.0) combinant : JA4↔UA, H2↔JA4, TCP↔UA, langue↔ASN, Sec-CH-UA↔UA |
|
||||
|
||||
#### Features TCP fenêtre
|
||||
|
||||
@ -466,38 +490,54 @@ Chaque anomalie reçoit un `campaign_id` (−1 = pas de cluster).
|
||||
```
|
||||
1. Requête view_ai_features_1h → DataFrame
|
||||
2. Enrichissement optionnel view_thesis_features_1h (features thèse §5)
|
||||
3. Prétraitement : preprocess_df() (nettoyage, browser axes, imputation)
|
||||
3. Prétraitement : preprocess_df() (nettoyage, browser axes 6, imputation)
|
||||
4. Chargement du feedback SOC → reclassification
|
||||
5. Chargement de la carte de récurrence (view_ip_recurrence)
|
||||
6. Séparation par correlated = 1 / correlated = 0
|
||||
7. Pour chaque modèle (Complet, Applicatif) :
|
||||
a. Validation des features (exclure constantes/manquantes)
|
||||
b. Séparation des bots connus → journalisation KNOWN_BOT
|
||||
c. Filtrage de la baseline humaine (asn_label = 'human')
|
||||
c. Filtrage de la baseline humaine (asn_label = 'human', fingerprint_coherence_score ≥ seuil)
|
||||
d. Chargement ou entraînement EIF + AE
|
||||
e. Scoring du trafic inconnu (EIF + AE)
|
||||
f. Chargement ou entraînement XGBoost (si labels disponibles)
|
||||
g. Combinaison des scores (formule triple voix)
|
||||
h. Normalisation [0, 1]
|
||||
i. Seuil adaptatif
|
||||
j. Pénalité de récurrence
|
||||
k. SHAP (top-3 features)
|
||||
l. HDBSCAN clustering → campaign_id
|
||||
m. Détection de dérive (KS test)
|
||||
8. Mode multi-fenêtre (si activé) : idem sur view_ai_features_24h
|
||||
9. Insertion → ml_all_scores (toutes les sessions scorées)
|
||||
10. Déduplication intra-cycle (garder raw_anomaly_score le plus bas par IP)
|
||||
11. Déduplication inter-cycle (TTL, skip si détecté récemment sauf aggravation ≥ 0.05)
|
||||
12. Insertion → ml_detected_anomalies (anomalies filtrées)
|
||||
g. MetaLearner : pondération apprise (logistique) sur historique SOC, sinon fallback poids fixes
|
||||
h. Combinaison des scores via MetaLearner ou formule fixe
|
||||
i. Normalisation [0, 1]
|
||||
j. Seuil adaptatif (percentile_5 des scores négatifs, minimum -0.05)
|
||||
k. Pénalité de récurrence
|
||||
l. ExIFFI (importance par profondeur d'isolation EIF) + erreur AE par feature
|
||||
m. SHAP top-5 TreeExplainer
|
||||
n. HDBSCAN clustering → campaign_id
|
||||
o. Détection de dérive (KS test + KL divergence)
|
||||
p. Alerte drift adversarial (dérive simultanée multiple features → direction commune)
|
||||
8. Analyse de flotte (fleet.py) : graphe bipartite JA4×ASN → communautés Louvain → fleet_score
|
||||
9. Mode multi-fenêtre (si activé) : idem sur view_ai_features_24h
|
||||
10. Insertion → ml_all_scores (toutes les sessions scorées)
|
||||
11. Déduplication intra-cycle (garder raw_anomaly_score le plus bas par IP)
|
||||
12. Déduplication inter-cycle (TTL, skip si détecté récemment sauf aggravation ≥ 0.05)
|
||||
13. Insertion → ml_detected_anomalies (anomalies filtrées)
|
||||
14. Insertion → fleet_detections (flottes détectées avec fleet_score)
|
||||
15. Enregistrement → ml_performance_metrics (métriques de cycle + alertes)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Détection de dérive (Kolmogorov-Smirnov)
|
||||
## Détection de dérive (KS + KL divergence)
|
||||
|
||||
Par feature, un **test KS bilatéral** compare la distribution courante avec la distribution d'entraînement (reconstruite par interpolation à partir d'un digest quantile p10/p25/p50/p75/p90) :
|
||||
Par feature, deux tests comparent la distribution courante avec la distribution d'entraînement :
|
||||
|
||||
**Test KS (Kolmogorov-Smirnov)** :
|
||||
- Distribution reconstruite par interpolation à partir d'un digest quantile 9 points (p5, p10, p25, p50, p75, p90, p95)
|
||||
- Feature driftée si `p_value < 0.05`
|
||||
|
||||
**Divergence KL (Kullback-Leibler)** :
|
||||
- Histogramme discrétisé (20 bins) de la distribution courante vs baseline
|
||||
- Feature driftée si `KL > seuil` (0.5 par défaut)
|
||||
- Détection de **drift adversarial** : si ≥30% des features dérivent simultanément dans la même direction → alerte `ADVERSARIAL_DRIFT`
|
||||
|
||||
**Règle de décision** : une feature est en drift si KS **ou** KL dépasse son seuil.
|
||||
|
||||
- Dérive globale = fraction de features driftées
|
||||
- Si `drift > DRIFT_THRESHOLD` (0.30) → réentraînement automatique
|
||||
|
||||
@ -505,13 +545,73 @@ Par feature, un **test KS bilatéral** compare la distribution courante avec la
|
||||
|
||||
---
|
||||
|
||||
## Explicabilité SHAP
|
||||
## MetaLearner
|
||||
|
||||
Lorsque `ENABLE_SHAP=true` et que la librairie `shap` est disponible :
|
||||
Remplace la pondération linéaire fixe `(1-XGB_W)×((1-AE_W)×eif + AE_W×ae) + XGB_W×xgb` par une régression logistique apprise (`scoring.MetaLearner`) :
|
||||
|
||||
- Calcul des valeurs SHAP via `TreeExplainer` sur le modèle EIF
|
||||
- Les **3 features les plus contributives** sont stockées dans le champ `reason`
|
||||
- Format : `"feature1=valeur (±shap), feature2=valeur (±shap), feature3=valeur (±shap)"`
|
||||
```
|
||||
P(bot) = logistic(w1×eif + w2×ae + w3×xgb + w4×volume + w5×correlated + bias)
|
||||
```
|
||||
|
||||
- **Entraînement** : sur l'historique `ml_all_scores` JOIN `soc_feedback` (labels SOC + KNOWN_BOT + ANUBIS_DENY + LEGITIMATE_BROWSER)
|
||||
- **Seuil** : activé seulement si ≥1000 labels disponibles — sinon fallback aux poids fixes
|
||||
- **Transparence** : poids appris journalisés dans `ml_performance_metrics` pour audit SOC
|
||||
- **Validation** : comparaison MetaLearner vs poids fixes sur split temporel (données postérieures à l'entraînement)
|
||||
|
||||
---
|
||||
|
||||
## ExIFFI et explicabilité augmentée
|
||||
|
||||
En complément de SHAP, le module expose deux méthodes d'importance de features spécifiques aux modèles utilisés :
|
||||
|
||||
**ExIFFI** (`compute_exiffi_importance`) :
|
||||
- Importance calculée par la profondeur moyenne d'isolation par feature dans l'EIF
|
||||
- Une feature avec profondeur d'isolation faible contribue fortement à l'anomalie
|
||||
- Corrèle avec SHAP mais capte des aspects complémentaires de la structure EIF
|
||||
|
||||
**Erreur AE par feature** (`compute_ae_feature_errors`) :
|
||||
- Reconstruction PyTorch feature par feature : `err_i = (x_i - x̂_i)²`
|
||||
- Pour chaque anomalie, les features avec la plus grande erreur de reconstruction sont identifiées
|
||||
- Expose quelles dimensions l'autoencoder ne parvient pas à reconstruire
|
||||
|
||||
Les deux méthodes sont disponibles dans le champ `shap_features` des résultats, en complément des valeurs SHAP TreeExplainer.
|
||||
|
||||
---
|
||||
|
||||
## Détection de flottes (fleet.py)
|
||||
|
||||
Détecte les **botnets coordonnés** utilisant des JA4 et ASN rotatifs via analyse de graphe bipartite :
|
||||
|
||||
1. **Construction du graphe** : nœuds JA4 ∪ ASN, arêtes IP observées dans le cycle
|
||||
2. **Projection** : projection du graphe bipartite sur les nœuds JA4
|
||||
3. **Communautés** : algorithme de Louvain (NetworkX) sur le graphe projeté
|
||||
4. **Score de flotte** : `fleet_score = taille_communauté × densité_arêtes / log(nb_ASN)`
|
||||
5. **Enrichissement** : les IPs membres reçoivent un malus proportionnel au fleet_score
|
||||
|
||||
Résultats stockés dans `fleet_detections` (TTL 7 jours). Exposés dans le dashboard via la page `/fleet`.
|
||||
|
||||
---
|
||||
|
||||
## Métriques de performance (metrics.py)
|
||||
|
||||
Enregistre par cycle dans `ml_performance_metrics` :
|
||||
|
||||
| Métrique | Description |
|
||||
|----------|-------------|
|
||||
| `anomaly_rate` | Taux d'anomalies détectées (cible : 0.5%–10%) |
|
||||
| `known_bot_rate` | Fraction KNOWN_BOT dans le cycle |
|
||||
| `legit_browser_rate` | Fraction LEGITIMATE_BROWSER |
|
||||
| `drift_rate` | Fraction de features en dérive |
|
||||
| `corr_rate` | Taux de sessions corrélées (cible : ≥50%) |
|
||||
| `cycle_latency_s` | Durée totale d'inférence (cible : <300s) |
|
||||
| `alert_flags` | Alertes émises (CALIBRATION_HIGH/LOW, DRIFT, CORRELATION, LATENCY) |
|
||||
|
||||
**Seuils d'alerte** :
|
||||
- `anomaly_rate > 10%` → `CALIBRATION_HIGH`
|
||||
- `anomaly_rate < 0.5%` → `CALIBRATION_LOW`
|
||||
- `drift_rate > 30%` → `DRIFT_ALERT`
|
||||
- `corr_rate < 50%` → `CORRELATION_ALERT`
|
||||
- `cycle_latency_s > 300` → `LATENCY_ALERT`
|
||||
|
||||
---
|
||||
|
||||
|
||||
Reference in New Issue
Block a user