Add run-e2e-test.sh with CLI parameters (--hits, --http-ratio, --dns, --tls, --src-ips, --keep-analysis, --up) for configurable traffic generation. Traffic runs from VM endpoints with multiple source IPs (alias IPs on eth0) to produce distinct sessions for the ML pipeline. Fix curl TLS flags (--tlsv1.2 instead of --tls-v1-2), skip redundant local verification in distributed mode, and fix dashboard is_available() cache that never retried after ClickHouse recovery. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
301 lines
19 KiB
Markdown
301 lines
19 KiB
Markdown
# Architecture
|
||
|
||
ja4-platform est un pipeline de sécurité qui capture le trafic réseau en temps réel, génère des empreintes TLS JA4/JA3, corrèle les handshakes TLS avec les requêtes HTTP, applique une détection d'anomalies par apprentissage automatique (ensemble triple voix), et présente les résultats dans un tableau de bord SOC. ClickHouse sert de magasin central reliant tous les services, organisé en deux bases de données distinctes.
|
||
|
||
## Architecture système
|
||
|
||
```
|
||
+---------------------------------------------------+
|
||
| Serveur Linux cible (Apache/Nginx/...) |
|
||
| |
|
||
| Client --HTTPS (443)--> [Serveur web] |
|
||
| Client --HTTP (80)---> [Serveur web] |
|
||
| |
|
||
| +-----------------+ |
|
||
| | ja4ebpf | (s'exécute sur le meme host)|
|
||
| | (eBPF CO-RE) | |
|
||
| | TC ingress |<-- L3/L4/L5 (SYN, TLS CH) |
|
||
| | uprobe SSL_read|<-- L7 HTTPS (déchiffré) |
|
||
| | kprobe tcp_recv|<-- L7 HTTP port 80/8080 |
|
||
| | 256-shard mgr | corrélation src_ip:src_port |
|
||
| +--------+--------+ |
|
||
| | |
|
||
+-----------|-----------------------------------+ |
|
||
| INSERT batch | |
|
||
v v
|
||
INSERT (Native TCP :9000)
|
||
▼
|
||
┌───────────────────────────────────────────────────────┐
|
||
│ ClickHouse 24.8 │
|
||
│ │
|
||
│ ja4_logs ja4_processing │
|
||
│ ┌────────────────┐ ┌────────────────────┐ │
|
||
│ │ http_logs_raw │──(MV)──▶ │ agg_host_ip_ja4_1h│ │
|
||
│ │ ↓ mv_http_logs │ agg_header_fp_1h │ │
|
||
│ │ http_logs │──(MVs)──▶│ agg_path_seq_1h │ │
|
||
│ └────────────────┘ │ agg_request_tm_1h│ │
|
||
│ │ agg_ip_behavior_1h│ │
|
||
│ │ agg_resource_cas_1h│ │
|
||
│ │ ml_detected_anom. │ │
|
||
│ │ ml_all_scores │ │
|
||
│ │ view_ai_features │ │
|
||
│ │ view_thesis_feat. │ │
|
||
│ │ audit_logs, dicts │ │
|
||
│ └────────────────────┘ │
|
||
└──────────┬──────────────────────────┬────────────────┘
|
||
│ SELECT │ SELECT / INSERT
|
||
┌──────────────┘ └──────────────┐
|
||
▼ ▼
|
||
┌───────────────────────┐ ┌───────────────────────┐
|
||
│ bot-detector │ │ dashboard │
|
||
│ Python 3.11 │ │ FastAPI + Jinja2 │
|
||
│ │ │ htmx + Chart.js │
|
||
│ Lit : │ │ Tailwind CSS (CDN) │
|
||
│ view_ai_features_1h │ │ │
|
||
│ view_thesis_feat_1h │ │ 53 routes (37 API │
|
||
│ view_ip_recurrence │ │ + 16 pages HTML) │
|
||
│ Écrit : │ │ 16 templates Jinja2 │
|
||
│ ml_detected_anomalies│ │ 16 pages SOC │
|
||
│ ml_all_scores │ │ │
|
||
│ fleet_detections │ │ Lit : ml_*, agg_*, │
|
||
│ ml_performance_metrics│ │ http_logs, audit_logs│
|
||
└───────────────────────┘ └───────────────────────┘
|
||
```
|
||
|
||
## Flux de données — 5 phases
|
||
|
||
### Phase 1 — Capture
|
||
|
||
1. **ja4ebpf TC ingress hook** capture les paquets réseau bruts. Pour chaque TCP SYN : `src_ip`, `src_port`, `ttl`, `window_size`, `mss`, `window_scale`, `df_bit`. Pour chaque TLS ClientHello : décodage du payload pour extraire `ciphers`, `extensions`, `elliptic_curves`, `alpn`, `sni` (calcul du hash JA4/JA3 en espace utilisateur Go).
|
||
|
||
2. **ja4ebpf uprobe SSL_read** accroche `SSL_read` dans la bibliothèque OpenSSL/BoringSSL du serveur web. Les données déchiffrées sont écrites dans un RingBuffer eBPF. Un kprobe sur `accept4` fournit la correspondance `fd → src_ip:src_port` pour annoter chaque buffer L7.
|
||
|
||
3. **ja4ebpf kprobe tcp_recvmsg** (HTTP port 80/8080) intercepte le payload TCP avant consommation par le serveur pour les connexions non chiffrées.
|
||
|
||
### Phase 2 — Corrélation en mémoire
|
||
|
||
4. **ja4ebpf 256-shard manager** (espace utilisateur Go) consomme les trois RingBuffers eBPF via des goroutines dédiées. Les événements L3/L4/L5 et L7 sont corrélés par `src_ip:src_port` dans une table de sessions shardée (256 shards, mutex par shard). Timeout orphelin : 500 ms (émission avec `correlated=0`). Détection Slowloris : émission partielle après 10 s. GC des sessions fantômes : toutes les 100 ms. Le dispatcher magic bytes route vers le parser HTTP/1.1 ou HTTP/2. Pour HTTP/2, la première frame SETTINGS + WINDOW_UPDATE est décodée pour le fingerprinting passif. L’objet corrélé est inséré dans **`ja4_logs.http_logs_raw`** par batch.
|
||
|
||
### Phase 3 — Enrichissement### Phase 3 — Enrichissement (ClickHouse)
|
||
|
||
4. **mv_http_logs** (vue matérialisée) transforme le JSON de `http_logs_raw` en la table structurée `ja4_logs.http_logs`, enrichissant chaque ligne avec :
|
||
- Données ASN via `dict_iplocate_asn` (IP_TRIE)
|
||
- Identification Anubis via `dict_anubis_ip` (IP_TRIE) et `dict_anubis_asn` (FLAT) — règles IP/CIDR + ASN uniquement, avec priorité COALESCE(IP, ASN)
|
||
|
||
5. **6 vues matérialisées d'agrégation** alimentent les tables `ja4_processing.agg_*` en fenêtres comportementales d'1 heure :
|
||
- `agg_host_ip_ja4_1h` — Agrégations par (host, src_ip, ja4)
|
||
- `agg_header_fingerprint_1h` — Empreintes d'en-têtes HTTP
|
||
- `agg_path_sequences_1h` — Séquences de chemins (n-grams)
|
||
- `agg_request_timing_1h` — Métriques de timing inter-requêtes
|
||
- `agg_ip_behavior_1h` — Comportement réseau par IP
|
||
- `agg_resource_cascade_1h` — Cascades de ressources
|
||
|
||
6. **view_ai_features_1h** joint les tables d'agrégation et calcule ~63 features ML par tuple `(src_ip, ja4, host)`.
|
||
|
||
### Phase 4 — Détection
|
||
|
||
7. **bot-detector** (Python 3.11, 16 modules) s'exécute en cycle de 5 minutes :
|
||
- **Pipeline bifurqué** :
|
||
- **Complet** (L3→L7, ~85 features, `correlated=1`) — trafic corrélé TCP+TLS+HTTP
|
||
- **Applicatif** (L7 seulement, ~73 features, `correlated=0`) — trafic HTTP non corrélé
|
||
- **Ensemble triple voix** :
|
||
- **Extended Isolation Forest** (isotree) — scoreur non supervisé principal
|
||
- **NFEnsemble** (PyTorch, Deep Ensemble M=5 TrafficNormalizingFlow/RealNVP) — NLL et incertitude épistémique
|
||
- **XGBoost** — supervisé, entraîné sur les labels SOC (`soc_feedback`)
|
||
- **Score final** : `final = meta_learner.predict(eif_norm, ae_norm, xgb_prob, volume, correlated)` avec fallback sur pondération linéaire fixe `(1-β) × ((1-α) × eif_norm + α × ae_norm) + β × xgb_prob` (α=0.30, β=0.20)
|
||
- **MetaLearner** (MLP) entraîné automatiquement sur les labels accumulés (seuil: 1000 labels)
|
||
- **Seuil adaptatif** par percentile, détection de dérive conceptuelle (ADWIN + KS + KL divergence)
|
||
- **Détection adversariale** : incertitude inter-modèles NFEnsemble (`nf_uncertainty > NF_UNCERTAINTY_THRESHOLD`)
|
||
- **fleet_detector** (PyTorch Geometric GraphSAGE) — graphe bipartite JA4×ASN, `fleet_score`, table `fleet_detections`
|
||
- **HDBSCAN** — regroupement en campagnes d'attaque
|
||
- **Détection de navigateur** — 6 axes multifactoriels (confiance ≥ 0.55 → `LEGITIMATE_BROWSER`)
|
||
- **ExIFFI** — importance de features native à l'EIF (alternative à SHAP)
|
||
- **Explicabilité SHAP** — contribution de chaque feature au score d'anomalie
|
||
- **Métriques de cycle** (`metrics.py`) — table `ml_performance_metrics`, alertes calibration
|
||
- **Niveaux de menace** : `CRITICAL`, `HIGH`, `MEDIUM`, `LOW`, `NORMAL`, `LEGITIMATE_BROWSER`, `KNOWN_BOT`, `ANUBIS_DENY`, `ANUBIS_ALLOW`
|
||
|
||
### Phase 5 — Visualisation
|
||
|
||
8. **dashboard** (FastAPI + Jinja2 + htmx + Chart.js + Tailwind CSS CDN) expose 53 routes (37 API JSON + 16 pages HTML) et 16 templates Jinja2 pour les analystes SOC :
|
||
- Pages : overview, detections, scores, traffic, ip_detail, ja4_detail, cluster_detail, campaigns, features, models, classify, tactics, reflists, network, fleet, health
|
||
|
||
## Matrice d'interaction des composants
|
||
|
||
| De ↓ \ Vers → | ja4ebpf | ClickHouse | bot-detector | dashboard |
|
||
|----------------|:---:|:---:|:---:|:---:|
|
||
| **ja4ebpf** | — | Native TCP :9000 (INSERT batch) | — | — |
|
||
| **ClickHouse** | — | MVs internes | — | — |
|
||
| **bot-detector** | — | HTTP :8123 (SELECT/INSERT) | — | — |
|
||
| **dashboard** | — | HTTP :8123 (SELECT/INSERT) | — | — |
|
||
|
||
## Propriété des tables ClickHouse
|
||
|
||
### Base `ja4_logs`
|
||
|
||
| Table / Vue | Écrit par | Lu par |
|
||
|-------------|-----------|--------|
|
||
| `http_logs_raw` | ja4ebpf | mv_http_logs (MV) |
|
||
| `http_logs` | mv_http_logs (MV) | mv_agg_* (6 MVs), dashboard |
|
||
| `mv_http_logs` | — (MV automatique) | — |
|
||
|
||
### Base `ja4_processing`
|
||
|
||
| Table / Vue | Écrit par | Lu par |
|
||
|-------------|-----------|--------|
|
||
| `agg_host_ip_ja4_1h` | mv_agg_host_ip_ja4_1h | view_ai_features_1h, dashboard |
|
||
| `agg_header_fingerprint_1h` | mv_agg_header_fingerprint_1h | view_ai_features_1h, dashboard |
|
||
| `agg_path_sequences_1h` | mv_agg_path_sequences_1h | view_thesis_features_1h |
|
||
| `agg_request_timing_1h` | mv_agg_request_timing_1h | view_thesis_features_1h |
|
||
| `agg_ip_behavior_1h` | mv_agg_ip_behavior_1h | view_thesis_features_1h |
|
||
| `agg_resource_cascade_1h` | mv_agg_resource_cascade_1h | view_thesis_features_1h |
|
||
| `ml_detected_anomalies` | bot-detector | dashboard |
|
||
| `ml_all_scores` | bot-detector | dashboard |
|
||
| `fleet_detections` | bot-detector (`fleet.py`) | dashboard |
|
||
| `ml_performance_metrics` | bot-detector (`metrics.py`) | dashboard |
|
||
| `soc_feedback` | dashboard (`/api/classify`) | bot-detector |
|
||
| `audit_logs` | dashboard | dashboard |
|
||
| `anubis_ip_rules` | fetch_rules.py | dict_anubis_ip |
|
||
| `anubis_asn_rules` | fetch_rules.py | dict_anubis_asn |
|
||
| `ref_bot_networks` | update-csv-data.sh | dict_bot_ip |
|
||
| `bot_ip` | update-csv-data.sh | dict_bot_ip |
|
||
| `bot_ja4` | update-csv-data.sh | dict_bot_ja4 |
|
||
| `view_ai_features_1h` | — (vue) | bot-detector |
|
||
| `view_ip_recurrence` | — (vue) | bot-detector |
|
||
| `view_thesis_features_1h` | — (vue) | bot-detector |
|
||
| `view_form_bruteforce_detected` | — (vue) | dashboard |
|
||
| `view_host_ip_ja4_rotation` | — (vue) | dashboard |
|
||
| `view_dashboard_user_agents` | — (vue) | dashboard |
|
||
| `view_dashboard_entities` | — (vue) | dashboard |
|
||
| `view_resource_cascade_1h` | — (vue) | dashboard |
|
||
|
||
### Dictionnaires (8)
|
||
|
||
| Dictionnaire | Layout | Source | Utilisation |
|
||
|--------------|--------|--------|-------------|
|
||
| `dict_iplocate_asn` | IP_TRIE | Fichier CSV | Géolocalisation IP → ASN |
|
||
| `dict_bot_ip` | IP_TRIE | Table `bot_ip` | IPs de bots connues |
|
||
| `dict_bot_ja4` | COMPLEX_KEY_HASHED | Table `bot_ja4` | Signatures JA4 de bots |
|
||
| `dict_browser_ja4` | COMPLEX_KEY_HASHED | Table (CSV) | Signatures JA4 de navigateurs |
|
||
| `dict_browser_h2` | COMPLEX_KEY_HASHED | Table (CSV) | Fingerprints HTTP/2 SETTINGS par navigateur |
|
||
| `dict_asn_reputation` | HASHED | Fichier CSV | Réputation ASN (isp/datacenter/hosting/cdn) |
|
||
| `dict_anubis_ip` | IP_TRIE | Table `anubis_ip_rules` | Règles Anubis IP/CIDR |
|
||
| `dict_anubis_asn` | FLAT | Table `anubis_asn_rules` | Règles Anubis ASN |
|
||
|
||
## Algorithme de corrélation
|
||
|
||
**ja4ebpf** corrèle les événements L3/L4/L5 (RingBuffer TC ingress) avec les événements L7 (RingBuffer uprobe) via une table de sessions en mémoire :
|
||
|
||
1. **Clé** : `src_ip + src_port` — l’IP source et le port éphémère identifient une connexion TCP de manière unique.
|
||
2. **Sharding** : 256 shards (`src_port % 256`), chacun protégé par un `sync.Mutex`. Réduit la contention sous fort trafic.
|
||
3. **Gestion Keep-Alive** : Un seul état TLS/L4 est conservé par connexion TCP et partagé entre toutes les requêtes HTTP successives. Compteur `maxkeepalives` incrémenté à chaque requête.
|
||
4. **Magic Bytes dispatcher** : Les premiers octets du buffer L7 déterminent le protocole :
|
||
- `PRI * HTTP/2.0\r\n` → parser HTTP/2 (SETTINGS + WINDOW_UPDATE + pseudo-headers)
|
||
- `GET `, `POST `, `HEAD `, etc. → parser HTTP/1.1
|
||
- Autre → `ProtoUnknown` (bruit TLS ou protocole non supporté)
|
||
5. **Orphelins** : Événements L7 sans correspondance L3/L4 dans les 500 ms → `correlated=0`.
|
||
6. **Slowloris** : Connexion TCP sans requête HTTP complète après 10 s → export partiel.
|
||
7. **GC** : Goroutine dédiée, itération sur tous les shards toutes les 100 ms.
|
||
|
||
La sortie est insérée dans **`ja4_logs.http_logs_raw`** (base `ja4_logs`), pas dans `ja4_processing`.
|
||
|
||
|
||
## Pipeline ML
|
||
## Pipeline ML — bot-detector (détail)
|
||
|
||
```
|
||
view_ai_features_1h ──┐ ┌─── ml_detected_anomalies
|
||
view_thesis_feat_1h ──┤ ┌────────────┐ │
|
||
view_ip_recurrence ───┤ │ Pré- │ │
|
||
├──▶│ traitement │──▶│ Bifurcation :
|
||
│ │ + filtrage │ │ ├── Complet (correlated=1, ~85 feat.)
|
||
│ └────────────┘ │ └── Applicatif(correlated=0, ~73 feat.)
|
||
│ │
|
||
│ ┌────────────┐ │ Pour chaque branche :
|
||
│ │ Ensemble │ │ ├── Extended Isolation Forest (EIF)
|
||
│ │ triple │──▶│ ├── NFEnsemble (M=5 NF, PyTorch)
|
||
│ │ voix │ │ └── XGBoost (supervisé)
|
||
│ └────────────┘ │
|
||
│ │ Score = MetaLearner(eif, ae, xgb) ou
|
||
│ │ (1-β)×((1-α)×EIF + α×AE) + β×XGB
|
||
│ ┌────────────┐ │
|
||
│ │ Post- │ ├─── ml_all_scores
|
||
└──▶│ traitement │──▶│
|
||
│ HDBSCAN │ │ Niveaux : CRITICAL / HIGH / MEDIUM /
|
||
│ fleet.py │ │ LOW / NORMAL / LEGITIMATE_BROWSER /
|
||
│ Browser 6ax│ │ KNOWN_BOT / ANUBIS_DENY / ANUBIS_ALLOW
|
||
│ ExIFFI+SHAP│ │
|
||
│ metrics.py │ ├─── fleet_detections
|
||
└────────────┘ └─── ml_performance_metrics
|
||
```
|
||
|
||
## Référence des empreintes JA4/JA3
|
||
|
||
### JA4
|
||
|
||
Format moderne de fingerprinting TLS (successeur de JA3) :
|
||
|
||
```
|
||
t{TLS_VER}{SNI}{CIPHER_COUNT}{EXT_COUNT}_{CIPHER_HASH}_{EXT_HASH}
|
||
```
|
||
|
||
Exemple : `t13d1516h2_8daaf6152771_b0da82dd1658`
|
||
|
||
- Préfixe `t` = TLS, suivi de la version (`13` = TLS 1.3)
|
||
- `d` = SNI présent, `i` = SNI absent
|
||
- Nombre de cipher suites et nombre d'extensions
|
||
- Hash SHA-256 tronqué des cipher suites et extensions triées
|
||
|
||
### JA3
|
||
|
||
Format original de fingerprinting TLS :
|
||
|
||
```
|
||
{TLS_VER},{CIPHERS},{EXTENSIONS},{ELLIPTIC_CURVES},{EC_POINT_FORMATS}
|
||
```
|
||
|
||
Le `ja3_hash` est le hash MD5 de la chaîne JA3.
|
||
|
||
Les deux empreintes sont générées par **ja4ebpf** (espace utilisateur Go) à partir du payload TLS ClientHello capturé par le TC ingress hook.
|
||
|
||
## Stack technologique
|
||
|
||
| Composant | Technologie |
|
||
|-----------|-------------|
|
||
| Capture réseau (L3/L4/L5) | Go 1.24.6 + eBPF CO-RE (TC ingress, cilium/ebpf) |
|
||
| Capture applicative (L7) | eBPF uprobe SSL_read + kprobe tcp_recvmsg |
|
||
| Corrélation en mémoire | Go 1.24.6 (256-shard manager, goroutines) |
|
||
| Détection ML — EIF | Python 3.11 + isotree |
|
||
| Détection ML — NFEnsemble | Python 3.11 + PyTorch |
|
||
| Détection ML — Supervisé | Python 3.11 + XGBoost |
|
||
| Détection ML — Ensemble | Python 3.11 + MetaLearner (MLP) |
|
||
| Clustering de campagnes | HDBSCAN + NetworkX (fleet detection) |
|
||
| Explicabilité | SHAP + ExIFFI |
|
||
| Backend dashboard | FastAPI + Jinja2 (Python 3.11) |
|
||
| Frontend dashboard | htmx + Chart.js + ECharts + Tailwind CSS (CDN) |
|
||
| Magasin de données | ClickHouse 24.8 (dual-database) |
|
||
| Déploiement | systemd, Docker, RPM (Rocky 8/9/10) |
|
||
| IPC | RingBuffers eBPF (kernel → userspace Go) |
|
||
| Workspace Go | `go.work` (Go 1.24.6) |
|
||
|
||
## Fichiers de schéma SQL (13)
|
||
|
||
```
|
||
shared/clickhouse/
|
||
├── 00_database.sql # Création des bases ja4_logs + ja4_processing
|
||
├── 01_raw_tables.sql # ja4_logs.http_logs_raw (TTL 2 heures)
|
||
├── 02_dictionaries.sql # dict_iplocate_asn, ref_bot_networks, bot_ip, bot_ja4
|
||
├── 03_anubis_tables.sql # anubis_ip_rules, anubis_asn_rules + 2 dictionnaires
|
||
├── 04_mv_http_logs.sql # ja4_logs.http_logs + mv_http_logs (JSON → colonnes)
|
||
├── 05_aggregation_tables.sql # agg_host_ip_ja4_1h, agg_header_fingerprint_1h + MVs + 4 dicts
|
||
├── 06_ml_tables.sql # ml_detected_anomalies, ml_all_scores, view_ip_recurrence
|
||
├── 07_ai_features_view.sql # view_ai_features_1h (feature engineering ~63 features)
|
||
├── 08_users.sql # Utilisateurs data_writer + analyst
|
||
├── 09_audit_table.sql # audit_logs (trace SOC, TTL 90 jours)
|
||
├── 10_perf_indexes.sql # Index et projections de performance
|
||
├── 11_views.sql # Vues métier du dashboard (4 vues)
|
||
├── 12_thesis_features.sql # agg_path_sequences, agg_request_timing, agg_ip_behavior,
|
||
│ # agg_resource_cascade + MVs + view_thesis_features_1h
|
||
│ # + view_resource_cascade_1h
|
||
└── deploy_schema.sh # Script de déploiement automatisé (substitution env vars)
|
||
```
|