- Add multi-interface TC attachment (default "any" = all UP interfaces) - Add BPF LPM_TRIE map ignored_src for kernel-side CIDR filtering - Add userspace ignore_src filtering for SSL/accept4 path via net.IPNet.Contains() - Add AcceptCache for fd→SessionKey correlation with TTL and Close() - Add 5 test files covering writer, procutil, dispatcher, accept_cache, and cmd - Fix formatTCPOptions infinite loop on EOL (case 0 break→return) - Fix pseudoOrderToShort panic on empty slice (negative cap) - Fix AcceptCache goroutine leak (add done channel + Close()) - Update config.yml.example with interfaces, listen_ports, ignore_src - Rewrite docs/services/ja4ebpf.md (was massively stale: XDP, RingBuffer, etc.) - Fix stale XDP/RingBuffer references in docs/architecture.md, thesis, tls.go Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
296 lines
25 KiB
Markdown
296 lines
25 KiB
Markdown
[<< Sommaire](README.md) | [Suivant >>](04_browser_matcher.md)
|
||
|
||
---
|
||
|
||
## 3. Architecture de détection multi-couches
|
||
|
||
### 3.1 Vue d'ensemble du pipeline
|
||
|
||
```
|
||
┌──────────────────────────────────────────────────────────────────┐
|
||
│ SOURCES DE DONNÉES │
|
||
├───────────────────────────┬──────────────────────────────────────┤
|
||
│ TC ingress │ uprobe SSL_read/SSL_write │
|
||
│ Couches L3/L4/L5 │ Couche L7 HTTP déchiffré │
|
||
│ │ │
|
||
│ │ │
|
||
│ réseau TC → │ Go Magic Bytes dispatcher → │
|
||
│ - SYN : TTL, IP-ID, DF, │ HTTP/1.1 : method, path, query, │
|
||
│ MSS, Window, Scale │ headers (bruts + ordre), │
|
||
│ - TLS ClientHello : │ status, taille, durée_ms, │
|
||
│ JA4, ALPN, SNI │ timestamp_ns (nanoseconde) │
|
||
│ - HTTP port 80/8080 │ HTTP/2 (depuis preface client) : │
|
||
│ │ ordre pseudo-headers │
|
||
│ │ WINDOW_UPDATE, PRIORITY flag, │
|
||
│ │ SETTINGS (7 params individuels), │
|
||
│ │ WINDOW_UPDATE, PRIORITY flag, │
|
||
│ │ ordre pseudo-headers │
|
||
└───────────────────────────┴──────────────────────────────────────┘
|
||
│ │
|
||
└─────────────┬─────────────┘
|
||
│
|
||
┌─────────▼─────────┐
|
||
│ Corrélation in-memory │
|
||
│ (ja4ebpf) │
|
||
│ Clé: src_ip:port │
|
||
│ Keep-Alive multi-│
|
||
│ request tracking │
|
||
│ Timeout orphelin │
|
||
│ 500ms │
|
||
│ L3/L4 ou L7 seul │
|
||
└─────────┬─────────┘
|
||
│
|
||
┌─────────▼─────────────────────────────┐
|
||
│ ClickHouse │
|
||
│ │
|
||
│ ja4_logs (brut, TTL 2h) │
|
||
│ ┌─────────────────────────────────┐ │
|
||
│ │ 13 fichiers SQL (00→12) │ │
|
||
│ │ AggregatingMergeTree views │ │
|
||
│ │ view_ai_features_1h │ │
|
||
│ │ view_thesis_features_1h │ │
|
||
│ │ agg_path_sequences_1h │ │
|
||
│ │ agg_request_timing_1h │ │
|
||
│ │ agg_resource_cascade_1h │ │
|
||
│ └─────────────────────────────────┘ │
|
||
│ ja4_processing (agrégé, TTL 7j) │
|
||
└─────────┬─────────────────────────────┘
|
||
│
|
||
┌─────────▼─────────────────────────────┐
|
||
│ bot_detector │
|
||
│ (16 modules Python, │
|
||
│ 4 800 lignes) │
|
||
│ │
|
||
│ Cycle 300s: │
|
||
│ ┌──────────────────────────────────┐ │
|
||
│ │ 1. Chargement features ClickHouse│ │
|
||
│ │ 2. dict lookups (IP, JA4, ASN) │ │
|
||
│ │ 3. browser_matcher scoring │ │
|
||
│ │ 3b. dynamic H2 profiling scoring │ │
|
||
│ │ 4. EIF bifurqué (complet/appli) │ │
|
||
│ │ 5. NF log-likelihood scoring │ │
|
||
│ │ 6. HAT probabilité (River online)│ │
|
||
│ │ 7. Fusion MLP non-linéaire │ │
|
||
│ │ 8. HDBSCAN clustering (NF latent) │ │
|
||
│ │ 9. Écriture résultats ClickHouse │ │
|
||
│ └──────────────────────────────────┘ │
|
||
└─────────┬─────────────────────────────┘
|
||
│
|
||
┌─────────▼─────────────────────────────┐
|
||
│ Dashboard │
|
||
│ (16 pages, 37 routes API) │
|
||
│ │
|
||
│ - Carte IP mondiale temps réel │
|
||
│ - Heatmaps temporelles │
|
||
│ - Top bots par famille │
|
||
│ - SHAP / ExIFFI feature importance │
|
||
│ - HDBSCAN cluster viewer │
|
||
│ - Graphes de flottes NetworkX │
|
||
└────────────────────────────────────────┘
|
||
```
|
||
|
||
**Composants clés** :
|
||
|
||
**uprobe eBPF** : mécanisme du noyau Linux permettant d'attacher dynamiquement une sonde eBPF à n'importe quelle fonction en espace utilisateur (par exemple `SSL_read` d'OpenSSL/BoringSSL), en utilisant l'infrastructure de breakpoints du noyau. L'uprobe intercepte l'appel à l'entrée ou à la sortie de la fonction cible, copie ses arguments ou sa valeur de retour dans un ring buffer eBPF, et rend le contrôle immédiatement — sans modifier le code source du processus cible, sans le mettre en pause, et sans nécessiter de recompilation. Dans **ja4ebpf**, l'uprobe sur `SSL_read` capture le buffer de données déchiffrées avant qu'il soit consommé par le serveur web (Apache, Nginx, Varnish, HAProxy), rendant l'interception totalement transparente côté applicatif.
|
||
|
||
**AggregatingMergeTree (ClickHouse)** : moteur de table ClickHouse spécialisé pour l'agrégation incrémentale. Contrairement à un merge ordinaire (qui fusionne des lignes brutes), il fusionne des états d'agrégation partiels (`AggregateFunction` columns) — permettant à `SUM`, `AVG`, `uniqCombined`, etc. d'être calculés correctement même si les données arrivent dans le désordre. Cela permet des vues matérialisées en temps réel à faible latence : chaque cycle d'insertion met à jour l'état partiel, et la vue finale est calculée à la demande en fusionnant tous les états partiels.
|
||
|
||
### 3.2 Couche L3 — IP et paquets
|
||
|
||
La couche L3 (couche réseau IP) fournit trois catégories de signaux :
|
||
|
||
**IP ID (Identification)** : champ 16 bits dans l'en-tête IP servant à l'identification unique des fragments IP. Valeur 0 (ou toujours identique) indique une pile TCP sans état ou une implémentation qui génère des paquets SYN sans identifiant séquentiel. Feature `ip_id_zero_ratio` : ratio de connexions avec IP ID = 0 dans la fenêtre de 300 secondes. Les scanners comme Masscan génèrent systématiquement IP ID = 0.
|
||
|
||
**TTL (Time to Live)** : champ 8 bits décrémenté par chaque routeur traversé. Quand TTL atteint 0, le paquet est rejeté et un message ICMP TTL Exceeded est envoyé à la source. Valeurs initiales par OS : Linux = 64, Windows = 128, iOS/macOS = 64. Après K sauts, TTL_observé = TTL_initial - K.
|
||
|
||
Features : `avg_ttl` (TTL moyen sur la fenêtre), `ttl_std` (écart-type du TTL — un TTL constant indique une topologie fixe ou une manipulation). Un TTL_observé divisible par 64 ou 128 selon le chemin réseau attendu valide l'OS déclaré ; une incohérence signale un VPN ou un tunnel qui modifie le TTL.
|
||
|
||
**DF bit (Don't Fragment)** : bit dans l'en-tête IP interdisant la fragmentation. Quand DF=1 et que le paquet est trop grand pour un lien, les routeurs retournent ICMP Fragmentation Needed. Linux utilise typiquement DF=1 (Path MTU Discovery actif). Certaines piles VPN utilisent DF=0. Feature `ip_df_variance` : variance du bit DF sur une session (instabilité anormale = stack réseau inhabituel).
|
||
|
||
### 3.3 Couche L4 — TCP
|
||
|
||
**TCP Keep-Alive et multiplexage HTTP** : à ne pas confondre avec HTTP Keep-Alive (`Connection: keep-alive`). Le TCP Keep-Alive est un mécanisme de détection de connexions mortes au niveau du noyau (envoi de paquets ACK vides après inactivité). L'HTTP Keep-Alive, en revanche, maintient la connexion TCP ouverte pour réutilisation par plusieurs requêtes HTTP successives. ja4ebpf trace le nombre de requêtes HTTP dans chaque connexion TCP via `max_keepalives` dans le gestionnaire de corrélation in-memory.
|
||
|
||
**Coefficient de variation (CV)** : mesure adimensionnelle de variabilité, CV = σ/μ. Un CV ≈ 0 indique une régularité élevée (automatisation à timer fixe) ; un CV ≈ 1–3 indique une variabilité naturelle (humain). Applicable à `syn_timing_cv` (variabilité du délai SYN→ClientHello) et à `cadence_cv` (variabilité des intervalles inter-requêtes).
|
||
|
||
**Features TCP** :
|
||
|
||
| Feature | Définition | Signal |
|
||
|---------|-----------|--------|
|
||
| `tcp_jitter_variance` | Variance des délais inter-connexions | Faible = automatisé à cadence fixe |
|
||
| `syn_timing_cv` | CV du délai SYN→TLS ClientHello | < 0.1 = script, > 0.5 = humain |
|
||
| `no_window_scale_ratio` | Ratio connexions sans Window Scale option | > 0.5 = stack TCP minimal ou obsolète |
|
||
| `tcp_shared_count` | Requêtes HTTP par connexion TCP (Keep-Alive) | 1 = bot sans Keep-Alive, >100 = bot pipeline |
|
||
| `port_exhaustion_ratio` | Ratio de ports source proches de l'épuisement (> 60000) | Injection rapide depuis un hôte unique |
|
||
| `src_port_density` | Densité des ports source (plage utilisée / connexions) | Faible = réutilisation systématique |
|
||
| `true_window_size` | Window Size × 2^window_scale | Fingerprint OS combiné |
|
||
| `window_mss_ratio` | true_window_size / MSS | Ratio diagnostique : écart = configuration non-standard |
|
||
|
||
### 3.4 Couche L5 — TLS
|
||
|
||
**Features TLS agrégées par session** :
|
||
|
||
| Feature | Définition | Valeur humain | Valeur bot |
|
||
|---------|-----------|---------------|------------|
|
||
| `tls12_ratio` | Ratio connexions TLS 1.2 / total TLS | ≈ 0 (Chrome/Firefox ≥1.3 exclusivement) | Variable selon outil |
|
||
| `fingerprint_coherence_score` | Cohérence JA4 à travers les connexions | ≈ 1 (même navigateur = même JA4) | < 0.5 si rotation JA4 |
|
||
| `is_alpn_missing` | 1 si ALPN absent dans ClientHello | Toujours 0 pour navigateurs | 1 pour stacks TLS minimalistes |
|
||
| `sni_host_mismatch` | 1 si SNI ≠ en-tête HTTP Host | 0 | > 0 si domain fronting ou proxy mal configuré |
|
||
| `distinct_ja4_count` | Nombre de JA4 distincts dans la session | 1 (un seul navigateur) | > 3 si rotation de pile TLS |
|
||
| `ja4_drift_ratio` | Transitions du JA4 dominant / (segments-1) | 0 | > 0.5 si changement intentionnel |
|
||
| `ja3_diversity_ratio` | Distinct JA3 / distinct JA4 | ≈ 1 | > 5 si randomisation GREASE anti-JA3 |
|
||
|
||
### 3.5 Couche L7 — HTTP
|
||
|
||
La couche L7 constitue la couche la plus riche en features comportementales. L'agent **ja4ebpf** capture le flux HTTP déchiffré via un uprobe sur `SSL_read` (OpenSSL/BoringSSL), avec une précision nanoseconde via `bpf_ktime_get_ns()`.
|
||
|
||
Données capturées par ja4ebpf : `src_ip`, `src_port`, `timestamp_ns` (nanoseconde absolu), `method`, `path`, `query_string`, `http_version`, `headers_raw` (en-têtes bruts dans leur ordre d'émission), `header_order_signature` (hash de l'ordre), `status_code`, `response_size`, `duration_ms`. L'horodatage nanoseconde est critique pour le calcul des features temporelles F8 (cadence_cv, lag1_autocorrelation, benford_deviation, root_to_first_asset_delay).
|
||
|
||
**Fingerprinting HTTP/2 passif intégré** : pour les connexions HTTP/2, l'uprobe sur `SSL_read` retourne un flux d'octets bruts déchiffrés qui **ne respecte pas les frontières des trames HTTP/2**. En raison de la fragmentation TCP et du buffering TLS, un seul appel `SSL_read` peut contenir un fragment partiel de trame, plusieurs trames complètes, ou une combinaison des deux. Le **Go Magic Bytes dispatcher** maintient donc un **buffer circulaire de réassemblage** par connexion (identifiée par `src_ip:src_port`) : il accumule les données de plusieurs appels `SSL_read` successifs jusqu'à ce que la logique de parsing HTTP/2 confirme qu'une trame complète est disponible (9 octets d'en-tête + longueur payload déclarée). L'identification du protocole HTTP/2 se fait en cherchant la connection preface `PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n` dans le buffer accumulé. Tout le parsing lourd — décodage des trames, HPACK pour les pseudo-headers — s'effectue dans l'agent Go en **espace utilisateur**, et non dans la VM eBPF (dont la complexité est limitée par le vérificateur noyau). Ce découplage est essentiel : la VM eBPF collecte les octets bruts le plus rapidement possible, et le parsing est réalisé de manière asynchrone côté Go sans jamais interrompre le flux applicatif du serveur web.
|
||
|
||
Une fois les trames complètes reconstituées, le parser Go en extrait les éléments suivants du preface client :
|
||
- Les 7 paramètres SETTINGS individuels (IDs 1–6 et 8), chacun stocké dans une colonne ClickHouse dédiée (`h2_header_table_size`, `h2_enable_push`, `h2_max_concurrent_streams`, `h2_initial_window_size`, `h2_max_frame_size`, `h2_max_header_list_size`, `h2_enable_connect_protocol`), avec la valeur -1 pour les paramètres absents du preface client
|
||
- L'incrément `h2_window_update` de la frame WINDOW_UPDATE sur la connexion (stream ID 0)
|
||
- Le flag `h2_has_priority` indiquant la présence d'un champ PRIORITY dans la frame HEADERS
|
||
- L'ordre des pseudo-headers `h2_pseudo_order` (ex. `m,a,s,p`) extrait par décodage HPACK partiel de la première frame HEADERS
|
||
- Le fingerprint composite `h2_fingerprint` au format Akamai et la chaîne brute `h2_settings_fp`
|
||
|
||
Les données H2 sont associées à la session courante via la clé `src_ip:src_port` dans le gestionnaire de corrélation in-memory de ja4ebpf, puis transmises en batch à ClickHouse avec les données TCP/TLS correspondantes.
|
||
|
||
**Colonnes HTTP/2 dans `ja4_logs.http_logs`** :
|
||
|
||
| Colonne ClickHouse | Type | Défaut | Description |
|
||
|---------------------|------|--------|-------------|
|
||
| `h2_fingerprint` | String | `''` | Fingerprint composite au format Akamai (ex. `1:65536,2:0,4:6291456,6:262144\|15663105\|0\|m,a,s,p`) |
|
||
| `h2_settings_fp` | String | `''` | Chaîne brute des entrées SETTINGS (ex. `3:100,4:65536,2:0`) |
|
||
| `h2_header_table_size` | Int32 | `-1` | SETTINGS ID 1 — HEADER_TABLE_SIZE (octets). -1 = absent du preface |
|
||
| `h2_enable_push` | Int32 | `-1` | SETTINGS ID 2 — ENABLE_PUSH (0/1). -1 = absent |
|
||
| `h2_max_concurrent_streams` | Int32 | `-1` | SETTINGS ID 3 — MAX_CONCURRENT_STREAMS. -1 = absent |
|
||
| `h2_initial_window_size` | Int64 | `-1` | SETTINGS ID 4 — INITIAL_WINDOW_SIZE (octets). -1 = absent |
|
||
| `h2_max_frame_size` | Int32 | `-1` | SETTINGS ID 5 — MAX_FRAME_SIZE (octets). -1 = absent |
|
||
| `h2_max_header_list_size` | Int32 | `-1` | SETTINGS ID 6 — MAX_HEADER_LIST_SIZE (octets). -1 = absent |
|
||
| `h2_enable_connect_protocol` | Int32 | `-1` | SETTINGS ID 8 — ENABLE_CONNECT_PROTOCOL (RFC 8441). -1 = absent |
|
||
| `h2_window_update` | UInt32 | `0` | Incrément WINDOW_UPDATE connexion (stream ID 0). 0 = absent |
|
||
| `h2_has_priority` | UInt8 | `0` | 1 si le flag PRIORITY est présent dans la frame HEADERS |
|
||
| `h2_pseudo_order` | String | `''` | Ordre des pseudo-headers (ex. `m,a,s,p` pour Chrome) |
|
||
|
||
La convention `-1` pour les paramètres SETTINGS absents est essentielle : elle distingue un paramètre non envoyé par le client (valeur par défaut RFC implicite) d'un paramètre explicitement fixé à 0 (ex. `ENABLE_PUSH = 0` signifie « Server Push désactivé » vs `-1` signifie « non envoyé, le serveur utilise la valeur par défaut RFC de 1 »).
|
||
|
||
Toutes les features des familles F1–F6 et F8 proviennent de cette couche, agrégées sur des fenêtres temporelles de 300 secondes (5 minutes) par session (src_ip).
|
||
|
||
### 3.6 Corrélation inter-couches (ja4ebpf)
|
||
|
||
**Clé de corrélation** : `(src_ip, src_port)` — le tuple source identifie de manière unique une connexion TCP à un instant donné (une connexion TCP est identifiée par le 4-tuple src_ip:src_port:dst_ip:dst_port, mais dst_ip:dst_port étant fixes pour un serveur, le 2-tuple src suffit).
|
||
|
||
**Gestion du HTTP Keep-Alive** : une connexion TCP peut transporter plusieurs requêtes HTTP successives. ja4ebpf maintient un gestionnaire de corrélation in-memory organisé en 256 shards (partitionnement par hash de src_ip pour éviter la contention). Chaque requête HTTP capturée via l'uprobe SSL_read est associée à l'enregistrement TCP/TLS ouvert correspondant, et `max_keepalives` est incrémenté. Un GC toutes les 100 ms libère les sessions expirées.
|
||
|
||
**Timeout orphelin** : si aucun enregistrement réseau (L3/L4) ne peut être associé à une requête HTTP dans les 500 ms — ce qui se produit quand le trafic arrive via un CDN ou un proxy inverse établissant une nouvelle connexion TCP entre le proxy et le serveur — la session est exportée avec uniquement les données HTTP disponibles. Les champs TCP/TLS restent absents dans l'enregistrement ClickHouse, et les features correspondantes sont imputées à zéro dans le pipeline ML.
|
||
|
||
**Conséquences pour le pipeline ML** : pour les sessions dont les données TCP/TLS sont absentes (proxy CDN, load balancer avec terminaison TLS), le Modèle Applicatif EIF (≈ 35 features L7 uniquement) est utilisé à la place du Modèle Complet (≈ 45 features L3→L7), évitant le biais d'imputation à zéro des features réseau.
|
||
|
||
**Impact sur HTTP/2** : quand `has_xff=1` (en-tête X-Forwarded-For présent, indiquant un proxy CDN), les dimensions H2 du browser_matcher sont neutralisées à 0.5 (score neutre). Le CDN réouvre sa propre connexion HTTP/2 vers le serveur d'origine ; les SETTINGS HTTP/2 capturés sont ceux du CDN (Cloudflare, Akamai), pas du client original.
|
||
|
||
**X-Forwarded-For** : en-tête HTTP ajouté par les proxies et load balancers pour préserver l'adresse IP du client original à travers la chaîne de proxies. Format : `X-Forwarded-For: client_ip, proxy1_ip, proxy2_ip`. Feature `has_xff` détecte la présence de cet en-tête.
|
||
|
||
### 3.7 Agrégation temporelle et features dérivées
|
||
|
||
**Cycle d'analyse** : 300 secondes (5 minutes). À chaque cycle, le bot_detector :
|
||
1. Interroge ClickHouse pour les features agrégées des sessions actives dans la dernière heure
|
||
2. Joint `view_ai_features_1h` (features L3–L6, corrélées) avec `view_thesis_features_1h` (features F8, temporelles)
|
||
3. Exécute le scoring ML
|
||
4. Écrit les résultats dans `ja4_processing`
|
||
|
||
**Vues matérialisées ClickHouse** :
|
||
|
||
| Vue | Contenu | Features extraites |
|
||
|-----|---------|-------------------|
|
||
| `view_ai_features_1h` | Features ML principales par session/heure | F1–F7 corrélées |
|
||
| `view_thesis_features_1h` | Features temporelles avancées | F8 (Benford, entropie, autocorrélation) |
|
||
| `agg_path_sequences_1h` | Séquences de chemins visités | session_transformer_embedding (via http_logs bruts), path_diversity |
|
||
| `agg_request_timing_1h` | Timing inter-requêtes en ms | cadence_cv, lag1_autocorrelation, burst_ratio |
|
||
| `agg_resource_cascade_1h` | Cascade de ressources (HTML→CSS→JS→images) | root_to_first_asset_delay, asset_load_stddev |
|
||
|
||
**TTL strategy** :
|
||
- **ja4_logs bruts : TTL 2h** — les logs bruts sont trop volumineux pour une conservation longue durée. Après 2 heures, les informations utiles ont été agrégées dans les vues.
|
||
- **ja4_processing agrégé : TTL 7j** — les features agrégées et les résultats de scoring sont conservés 7 jours pour l'analyse de tendances, la corrélation de campagnes, et l'entraînement des modèles.
|
||
|
||
**Métriques de déploiement** : > 3 millions de logs ingérés, ≈ 34 000 sessions par cycle de 300 s, ≈ 777 anomalies détectées par cycle (≈ 2,3 %), cycle d'analyse 300 s.
|
||
|
||
### 3.8 Détection ML semi-supervisée (full pipeline)
|
||
|
||
#### Trifurcation du trafic
|
||
|
||
```
|
||
Session entrante
|
||
│
|
||
├── dict_bot_ip CIDR match ?
|
||
│ OU dict_bot_ja4 match ?
|
||
│ OU Anubis DENY ?
|
||
│ ── OUI → KNOWN_BOT (étiquette entraînement XGB)
|
||
│
|
||
├── browser_matcher score ≥ seuil ?
|
||
│ (Chrome ≥ 0.72, Firefox/Safari ≥ 0.68)
|
||
│ ET aucune signature négative ?
|
||
│ ── OUI → LEGITIMATE_BROWSER
|
||
│
|
||
├── Zone grise [0.45, seuil[ ?
|
||
│ ── OUI → score_final × (1 - 0.5 × match_score)
|
||
│ (pénalité partielle, pas de blocage)
|
||
│
|
||
├── asn_label == 'human' ?
|
||
│ ── OUI → baseline EIF training (sans étiquette bot)
|
||
│
|
||
└── Sinon → Triple-voix : EIF + NF + HAT (River) + Fusion MLP non-linéaire
|
||
```
|
||
|
||
#### Seuil adaptatif
|
||
|
||
```python
|
||
threshold = min(percentile_5(neg_scores_history), -0.05)
|
||
```
|
||
|
||
La valeur `percentile_5` du historique des scores négatifs (anomalies confirmées) établit un seuil qui capture au moins le top 5 % des anomalies observées récemment. Le plancher `-0.05` garantit une sensibilité minimale même lors de périodes de faible activité botique. Cette adaptation évite les faux négatifs systémiques en période calme et les faux positifs en période d'activité élevée.
|
||
|
||
#### Scoring bifurqué
|
||
|
||
| Modèle | Features | Trafic applicable | Indicateur |
|
||
|--------|----------|-------------------|------------|
|
||
| EIF Complet | ≈ 45 features L3→L7 | Données L3/L4 disponibles | eif_score_full |
|
||
| EIF Applicatif | ≈ 35 features L7 | L3/L4 absentes (CDN/proxy) | eif_score_app |
|
||
| NF | Même dimensionnalité que EIF actif | Toutes sessions | nf_log_likelihood |
|
||
| HAT (River) | Ensemble complet 96 features | Toutes sessions | hat_probability |
|
||
|
||
#### Niveaux de sévérité
|
||
|
||
| Étiquette | Condition | Action recommandée |
|
||
|-----------|-----------|-------------------|
|
||
| CRITICAL | score_final < -0.30 | Blocage immédiat + alerte SOC |
|
||
| HIGH | score_final < -0.15 | Blocage + journalisation |
|
||
| MEDIUM | score_final < -0.05 | CAPTCHA challenge + journalisation |
|
||
| LOW | score_final < 0 | Journalisation + surveillance accrue |
|
||
| KNOWN_BOT | Match dict_bot_ip / dict_bot_ja4 / Anubis DENY | Blocage + label entraînement |
|
||
| ANUBIS_DENY | Règle Anubis DENY explicite | Blocage + label entraînement |
|
||
| LEGITIMATE_BROWSER | browser_matcher ≥ seuil | Passage sans friction |
|
||
|
||
#### HDBSCAN pour le clustering de campagnes
|
||
|
||
[HDBSCAN (Hierarchical Density-Based Spatial Clustering of Applications with Noise, Campello, Moulavi, Sander, 2013)](https://link.springer.com/chapter/10.1007/978-3-642-37456-2_14) est un algorithme de clustering hiérarchique basé sur la densité. Il étend DBSCAN (Density-Based Spatial Clustering of Applications with Noise) en :
|
||
|
||
1. Calculant la matrice de distances de réachabilité mutuelle (mutual reachability distance) : `d_mreach(a,b) = max(core_k(a), core_k(b), d(a,b))` où `core_k(x)` est la distance au k-ème voisin le plus proche
|
||
2. Construisant l'arbre couvrant minimal (Minimum Spanning Tree, MST) sur cette matrice
|
||
3. Transformant le MST en une hiérarchie de clusters à tous les niveaux de densité
|
||
4. Extrayant les clusters les plus stables par un score de persistance : `stability(C) = Σ_{x ∈ C} (λ_death(x,C) - λ_birth(C))`
|
||
5. Assignant les points non intégrés à la classe bruit (-1)
|
||
|
||
**Avantages sur DBSCAN** : gère les clusters de densités variables, ne nécessite que `min_cluster_size` (pas d'ε), robuste au bruit.
|
||
|
||
**Application dans l'architecture** : HDBSCAN est appliqué sur l'espace latent AE de 16 dimensions. Les sessions dont la représentation latente est proche correspondent à des bots utilisant le même outil ou la même configuration. Le clustering regroupe ces sessions en campagnes identifiables, permettant de :
|
||
- Détecter les campagnes distribuées sur plusieurs adresses IP
|
||
- Lier des sessions séparées par des gaps temporels (même campagne qui reprend)
|
||
- Fournir des contextes de menace au SOC (« cluster #7 = 34 IPs, JA4 identique, asset_ratio ≈ 0 »)
|
||
|
||
---
|
||
|
||
|
||
---
|