feat(ml): replace NetworkX/Louvain with PyTorch Geometric GraphSAGE for fleet detection

Rewrite fleet.py to use a GNN-based approach: nodes are src_ip with ML feature
vectors, edges connect IPs sharing (JA4, ASN) pairs, GraphSAGE (2 SAGEConv
layers, in→64→32) produces 32D embeddings clustered by HDBSCAN. PyG NeighborLoader
activates for >50k nodes. Update thesis docs (§5.2, §6.4, §2, §8) to reflect
GraphSAGE architecture and PyG scalability.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Jacquin Antoine
2026-04-13 15:45:34 +02:00
parent c1821dcbc4
commit c6cb12981c
8 changed files with 378 additions and 264 deletions

View File

@ -114,18 +114,19 @@ Le fingerprinting réseau opère sans déchiffrement TLS (les métadonnées TLS
| HDBSCAN (anomalies) | ~100 ms | ~34 000 sessions, espace latent AE |
| HDBSCAN (profiling) | ~25 s | Quotidien, ~200k sessions H2 dédupliquées, min_cluster=1000 |
| Dynamic matcher scoring | < 1 ms | Par session, lookup en mémoire contre ~510 profils |
| Louvain (fleet.py) | ~50 ms | Graphe JA4×ASN, communautés |
| GraphSAGE (fleet.py) | ~80 ms | Graphe d'IPs, 2 couches SAGEConv, GPU/CPU |
| Fusion LR LR | < 10 ms | Régression logistique, négligeable |
| **Cycle complet** | **~300 secondes** | EIF + AE + XGBoost + HDBSCAN + Louvain |
| **Cycle complet** | **~300 secondes** | EIF + AE + XGBoost + HDBSCAN + GraphSAGE |
La durée du cycle (300 s = 5 minutes) est contrainte principalement par la **fenêtre d'agrégation ClickHouse** (1 heure glissante avec recalcul toutes les 5 minutes), non par les temps d'exécution ML.
#### Limites de scalabilité
**fleet.py — graphe NetworkX** :
- Complexité mémoire : O(V + E) V = nombre de nœuds JA4 + ASN, E = nombre d'arêtes
- À 100 000 JA4/ASN distincts par cycle, la mémoire devient contraignante (~4 Go pour un graphe dense)
- **Mitigation** : représentation en matrice sparse (scipy.sparse), réinitialisation du graphe à chaque cycle, seuil minimum d'arêtes (min_ips = 3)
**fleet.py — graphe d'IPs avec PyTorch Geometric** :
- Le module utilise **PyTorch Geometric** (PyG) pour la construction et l'inférence du graphe, éliminant toute dépendance à NetworkX
- En full-batch (≤ 50 000 nœuds) : les tensors (`x`, `edge_index`) résident en mémoire GPU/CPU de manière compacte (COO sparse), complexité O(V + E)
- Au-delà de 50 000 nœuds, le **Neighbor Sampling** (`NeighborLoader`) échantillonne le voisinage de chaque mini-batch (num_neighbors=[25, 10], batch_size=4096), réduisant la complexité mémoire à O(batch × k²) par batch indépendant de la taille du graphe
- **Scalabilité théorique** : des graphes de millions de nœuds (infrastructure CDN, trafic massif) restent traitables sur GPU standard, PyG exploitant les opérations scatter/gather vectorisées CUDA
**HDBSCAN sur l'espace latent AE** :
- Complexité temporelle : O(n log n) pour n sessions
@ -144,7 +145,7 @@ Analyse systématique des limites de chaque technique proposée, avec quantifica
| Technique | Limite principale | Condition de déclenchement | Mesure d'atténuation |
|-----------|-------------------|---------------------------|---------------------|
| **5.1** Path Sequence Entropy | Nécessite une session longue (> 5 requêtes) pour une entropie fiable | Sessions de courte durée, bots single-request | Fallback vers `path_diversity_ratio` pour sessions < 5 requêtes |
| **5.1** Session Transformer Embedding | Nécessite ≥ 2 requêtes pour un embedding non-nul ; qualité dépendante du pré-entraînement | Sessions single-request, modèle non entraîné | Fallback vers vecteur nul (32 zéros) pour sessions ≤ 1 requête |
| **5.2** Bipartite Fleet Graph | Contrainte mémoire O(V+E) à l'échelle | > 100k JA4/ASN distincts par cycle | Représentation sparse, seuil `min_ips`, réinitialisation par cycle |
| **5.3** Cadence Fingerprint | Insuffisant pour les sessions single-request | Bots qui font exactement 1 requête par cycle | Agrégation des sessions multi-cycles par IP sur 24h |
| **5.4** Resource Dependency Tree | Requiert une classification correcte Content-Type/extension | Chemins sans extension, Content-Type ambigu (`*/*`) | Double-source : en-tête Accept + regex extension chemin |