Files
ja4-platform/docs/services/dashboard.md
toto 85d3b95b7b feat: HTTP/2 passive fingerprinting with individual SETTINGS fields
Complete implementation of HTTP/2 passive fingerprinting per thesis §2.5.3:

mod-reqin-log (C module):
- Replace connection-level filter with ap_hook_process_connection (APR_HOOK_FIRST)
  to capture H2 preface before mod_http2 takes over the connection
- AP_MODE_SPECULATIVE read of 512 bytes from c->input_filters
- Parse SETTINGS, WINDOW_UPDATE, PRIORITY flags, pseudo-header order
- Output individual SETTINGS params as separate JSON fields (IDs 1-6, 8)
- Read H2 notes from c1 (master connection) for mod_http2 secondary conns
- Fix header_order_signature JSON length bug (26→strlen)

ClickHouse schema:
- Add 8 new columns to http_logs: h2_has_priority, 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
- Use Int32/Int64 with DEFAULT -1 to distinguish absent vs zero
- Update mv_http_logs to extract individual fields via JSONHas/JSONExtractInt
- Migration 04_http2_fields.sql updated for existing deployments

Correlator:
- Accept both timestamp_ns and timestamp field names (backward compat)

Integration:
- Enable HTTP/2 in Apache: Protocols h2 http/1.1 in httpd-integration.conf

Validated end-to-end via Playwright: H2 curl traffic → mod-reqin-log →
correlator → ClickHouse with all 12 H2 columns populated correctly.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-04-11 02:33:45 +02:00

16 KiB
Raw Blame History

Dashboard

Application web SOC (Security Operations Center) construite avec FastAPI + Jinja2 + ECharts, offrant la visualisation en temps réel, l'investigation et l'analyse des détections de bots générées par le bot-detector. Interroge ClickHouse sur deux bases de données (ja4_processing et ja4_logs).


Pile technologique

Composant Technologie
Backend Python 3.11 + FastAPI
Templates Jinja2 (rendu côté serveur)
Interactions dynamiques Vanilla fetch() (appels JSON API avec rechargement partiel côté JS)
Graphiques ECharts 5.5 (CDN)
Style Tailwind CSS (CDN)
Base de données ClickHouse via clickhouse-connect (client propre, PAS ja4_common)
Documentation API Swagger UI (/docs) + OpenAPI JSON (/openapi.json)

Note : le dashboard n'utilise pas la bibliothèque partagée ja4_common. Il possède son propre client ClickHouse léger dans backend/database.py.


Structure des fichiers

services/dashboard/
├── backend/
│   ├── __init__.py
│   ├── main.py            Application FastAPI, montage templates + static, CORS, health
│   ├── config.py           Variables d'environnement, safe_identifier()
│   ├── database.py         Client clickhouse-connect singleton, query(), query_scalar(), execute()
│   └── routes/
│       ├── __init__.py
│       ├── api.py          37 routes JSON (1700+ lignes)
│       └── pages.py        16 routes de pages HTML (100+ lignes)
├── templates/
│   ├── base.html           Template de base (layout, navigation, Tailwind CDN)
│   ├── overview.html       Vue d'ensemble du dashboard
│   ├── detections.html     Tableau paginé des détections d'anomalies
│   ├── scores.html         Tableau paginé de tous les scores ML
│   ├── traffic.html        Tableau paginé du trafic HTTP brut
│   ├── ip_detail.html      Investigation détaillée d'une IP
│   ├── ja4_detail.html     Investigation détaillée d'une empreinte JA4
│   ├── cluster_detail.html Investigation détaillée d'un cluster/campagne
│   ├── campaigns.html      Vue des campagnes HDBSCAN
│   ├── features.html       Analyse des features ML
│   ├── models.html         Métadonnées et performances des modèles
│   ├── classify.html       Interface de classification SOC
│   ├── tactics.html        Tactiques de détection (brute-force, rotation, récurrence)
│   ├── reflists.html       Listes de référence et dictionnaires ClickHouse
│   ├── network.html        Graphe réseau des campagnes
│   ├── fleet.html          Détections de flottes coordonnées (graphe bipartite)
│   └── health.html         Santé du pipeline — métriques de performance par cycle
└── static/                 Fichiers statiques (JS, CSS)

Configuration

Toute la configuration est lue via os.getenv() dans backend/config.py.

Variable Type Défaut Description
CLICKHOUSE_HOST str localhost Nom d'hôte du serveur ClickHouse
CLICKHOUSE_PORT int 8123 Port HTTP ClickHouse
CLICKHOUSE_USER str default Utilisateur ClickHouse
CLICKHOUSE_PASSWORD str "" Mot de passe ClickHouse
CLICKHOUSE_DB_PROCESSING str ja4_processing Base de données ML/agrégations (fallback : CLICKHOUSE_DB)
CLICKHOUSE_DB_LOGS str ja4_logs Base de données des logs HTTP
API_HOST str 0.0.0.0 Adresse d'écoute du serveur
API_PORT int 8000 Port d'écoute du serveur

Schéma dual-database

Le dashboard utilise deux bases de données ClickHouse :

  • CLICKHOUSE_DB_PROCESSING (ja4_processing) : tables ML, agrégations, dictionnaires, feedback SOC
  • CLICKHOUSE_DB_LOGS (ja4_logs) : http_logs, trafic brut

Les noms de bases sont validés par safe_identifier() (regex alphanumérique + underscore) avant injection dans les requêtes SQL.

Dualité IPv4/IPv6

  • http_logs.src_ip est de type IPv4
  • Les tables ML (ml_all_scores, ml_detected_anomalies) stockent IPv6 (mappé ::ffff:x.x.x.x)
  • Utiliser toIPv6() pour les requêtes sur les tables ML
  • Utiliser toIPv4OrZero() pour les requêtes sur http_logs
  • Retirer le préfixe ::ffff: à l'affichage

Couche base de données (backend/database.py)

Client clickhouse-connect avec singleton paresseux :

Fonction Signature Description
get_client() → Client Singleton clickhouse_connect.get_client()
query(sql, params) → list[dict] Exécute un SELECT, retourne une liste de dicts
query_scalar(sql, params) → Any Exécute un SELECT, retourne une valeur scalaire
execute(sql, params) → None Exécute un DDL/DML sans retour

Conversion automatique des types : IPv4Address, IPv6Address, bytes → chaînes JSON-friendly.

Patron de requêtes paramétrées

from backend.config import DB_PROCESSING, DB_LOGS, safe_identifier
from backend.database import query, query_scalar

_DB = safe_identifier(DB_PROCESSING)
rows = query(
    f"SELECT src_ip, anomaly_score FROM {_DB}.ml_detected_anomalies "
    "WHERE src_ip = toIPv6({ip:String}) ORDER BY detected_at DESC LIMIT 10",
    {"ip": ip_value},
)

Routes de pages (16)

Toutes les pages sont rendues côté serveur via Jinja2 et utilisent htmx pour les mises à jour dynamiques.

# Chemin Template Description
1 / overview.html Vue d'ensemble : statistiques 24h, distribution des menaces, top IPs, timeline
2 /detections detections.html Tableau paginé des détections d'anomalies avec filtres
3 /scores scores.html Tableau paginé de tous les scores ML avec filtres
4 /traffic traffic.html Tableau paginé des logs HTTP bruts avec filtres
5 /ip/{ip} ip_detail.html Investigation détaillée d'une IP (détections, scores, logs, features, récurrence)
6 /classify classify.html Interface de classification SOC (feedback analyste)
7 /features features.html Analyse des features ML (profils humain/bot, importance)
8 /models models.html Métadonnées des modèles, statistiques de scoring
9 /network network.html Graphe réseau des campagnes (IP ↔ JA4 partagés)
10 /campaigns campaigns.html Campagnes HDBSCAN (clusters de bots agrégés)
11 /ja4/{fingerprint:path} ja4_detail.html Investigation détaillée d'une empreinte JA4
12 /cluster/{cid} cluster_detail.html Investigation détaillée d'un cluster
13 /tactics tactics.html Tactiques de détection (brute-force, rotation JA4/UA, récurrence)
14 /reflists reflists.html Listes de référence et dictionnaires ClickHouse
15 /fleet fleet.html Détections de flottes coordonnées — graphe bipartite JA4×ASN, communautés, fleet_score
16 /health health.html Santé du pipeline — métriques de cycle, alertes calibration/drift/corrélation/latence

Routes API (37)

Toutes les routes sont préfixées par /api et retournent du JSON. Utilisées par htmx depuis les templates et consommables par des clients externes.

Vue d'ensemble et statistiques

# Méthode Chemin Description
1 GET /api/overview Résumé du dashboard : détections/scores/trafic 24h, distribution des menaces, top IPs, timeline, modèles, statistiques navigateur
2 GET /api/heatmap Heatmap temporelle (heure × jour de semaine) depuis http_logs
3 GET /api/geo Répartition géographique et ASN des sessions
4 GET /api/alerts Flux d'alertes en direct (détections récentes HIGH/CRITICAL)
5 GET /api/timeline-detail Détail horaire de la timeline par niveau de menace

Détections et scores

# Méthode Chemin Description
6 GET /api/detections Liste paginée des détections d'anomalies avec filtres (threat_level, search, asn, country, ja4, bot, browser) et tri
7 GET /api/scores Liste paginée des scores ML avec filtres similaires
8 GET /api/traffic Liste paginée des logs HTTP bruts avec filtres

Investigation IP

# Méthode Chemin Description
9 GET /api/ip/{ip} Détail IP : détections, scores, logs HTTP, features AI, récurrence
10 GET /api/ip/{ip}/radar Données pour graphique radar : IP vs baseline ISP vs baseline bot

Features et modèles

# Méthode Chemin Description
11 GET /api/features Statistiques des features AI/thèse, profils humain/bot, importance (variance)
12 GET /api/models Métadonnées des modèles depuis fichiers JSON + statistiques de scoring ClickHouse
13 GET /api/models/timeline Volume horaire de scoring par modèle (7 jours)
14 GET /api/models/threats Répartition des niveaux de menace par modèle

Empreintes et navigateurs

# Méthode Chemin Description
15 GET /api/fingerprints Analyse des empreintes JA4 avec mapping de bots
16 GET /api/browsers Distribution des familles de navigateurs via JA4
17 GET /api/behavior Données scatter des features comportementales + distributions

Classification SOC

# Méthode Chemin Description
18 GET /api/classify/stats Résumé statistique des classifications SOC
19 GET /api/classify/suggested Top des IPs non classifiées triées par sévérité
20 POST /api/classify Soumettre un feedback analyste SOC (bot/legitimate/suspicious)
21 GET /api/classifications Entrées de feedback SOC récentes

Campagnes et clusters

# Méthode Chemin Description
22 GET /api/campaigns Clusters de campagnes HDBSCAN (agrégés)
23 GET /api/campaigns/graph Données de graphe réseau (nœuds IP + arêtes JA4 partagés)
24 GET /api/campaigns/scatter Scatter plot : score d'anomalie vs vélocité par IP et campagne
25 GET /api/campaigns/{cid} Détail campagne : membres, profil, timeline

Investigation JA4 et cluster

# Méthode Chemin Description
26 GET /api/ja4/{fingerprint:path} Investigation d'empreinte JA4 (IPs, scores, logs, features)
27 GET /api/cluster/{cid} Investigation enrichie de cluster (profil, membres, graphe, répartitions)

Tactiques de détection

# Méthode Chemin Description
28 GET /api/brute-force Détection de brute-force / credential stuffing
29 GET /api/ja4-rotation Détection de rotation d'empreintes JA4 (évasion)
30 GET /api/recurrence IPs de menaces persistantes/récurrentes
31 GET /api/cascade/{ip} Cascade de ressources pour détection de navigateur headless
32 GET /api/ua-rotation Détection de rotation de User-Agent

Flottes et santé

# Méthode Chemin Description
33 GET /api/fleet Flottes de bots coordonnées — communautés JA4×ASN, fleet_score, IPs membres
34 GET /api/health Métriques de performance du pipeline — cycle, drift, corrélation, alertes

Dictionnaires et listes de référence

# Méthode Chemin Description
35 GET /api/dictionaries Métadonnées des 8 dictionnaires ClickHouse
36 GET /api/reflist/{name} Contenu paginé d'une liste de référence / dictionnaire
37 GET /api/reflist/{name}/stats Statistiques agrégées d'une liste de référence

Autres routes

Méthode Chemin Description
GET /health Point de santé — retourne l'état de connexion ClickHouse
/static Montage de fichiers statiques (backend/static/)
GET /docs Documentation Swagger UI (auto-généré par FastAPI)
GET /openapi.json Schéma OpenAPI (auto-généré par FastAPI)

Total : 16 pages + 37 API + 1 health check = 54 routes applicatives


Paramètres de requête courants

Les endpoints paginés (/api/detections, /api/scores, /api/traffic) acceptent :

Paramètre Type Description
page int Numéro de page (défaut : 1)
page_size int Éléments par page (défaut : 20)
threat_level str Filtre par niveau de menace
model_name str Filtre par nom de modèle
search str Recherche plein texte (IP, JA4, host, bot_name)
sort_by str Champ de tri (validé contre une whitelist)
sort_order str asc ou desc

Workflow SOC

Le dashboard est conçu pour le workflow d'un analyste SOC :

  1. Vue d'ensemble (/) — identifier les tendances de menaces 24h, les pics d'anomalies
  2. Détections (/detections) — filtrer les anomalies par sévérité, rechercher des IPs spécifiques
  3. Investigation IP (/ip/{ip}) — examiner les détections, scores, logs HTTP, features ML, radar de comparaison
  4. Analyse JA4 (/ja4/{fp}) — investiguer une empreinte TLS, voir toutes les IPs associées
  5. Campagnes (/campaigns) — visualiser les clusters de bots, graphe réseau, scatter plot
  6. Cluster (/cluster/{cid}) — plonger dans un cluster spécifique, examiner les membres et profils
  7. Flottes (/fleet) — visualiser les communautés de botnets coordonnées (graphe bipartite JA4×ASN)
  8. Tactiques (/tactics) — surveiller le brute-force, la rotation JA4/UA, les menaces récurrentes
  9. Classification (/classify) — soumettre un feedback analyste (bot/légitime/suspect) pour alimenter XGBoost et le MetaLearner
  10. Features (/features) — comparer les profils de features humain vs bot
  11. Modèles (/models) — surveiller les performances des modèles ML
  12. Santé (/health) — métriques de cycle, alertes de calibration, drift, corrélation et latence

Architecture des templates

Template de base (base.html)

Fournit le layout commun :

  • Navigation latérale avec liens vers toutes les pages
  • Chargement CDN de Tailwind CSS, htmx, Chart.js, ECharts
  • Bloc {% block content %} pour le contenu de chaque page

Rendu côté serveur + htmx

Chaque page est rendue côté serveur par Jinja2. Les interactions dynamiques utilisent htmx :

<!-- Exemple : chargement dynamique des détections -->
<div hx-get="/api/detections?page=1&page_size=20"
     hx-trigger="load"
     hx-target="#detections-table">
</div>

Les graphiques sont rendus côté client par Chart.js et ECharts à partir des données JSON de l'API.


CORS

Le middleware CORS est configuré de manière permissive dans main.py :

app.add_middleware(
    CORSMiddleware,
    allow_origins=["*"],
    allow_credentials=True,
    allow_methods=["*"],
    allow_headers=["*"],
)

L'application est principalement SSR mais l'API JSON est aussi consommable par des clients externes.


Déploiement

# Construction de l'image Docker
make build-dashboard

# Tests
make test-dashboard

# Exécution locale (développement)
cd services/dashboard
uvicorn backend.main:app --reload --host 0.0.0.0 --port 8000

Point de santé

GET /health → {"status": "healthy", "clickhouse": "connected"}