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>
16 KiB
Dashboard
Application web SOC (Security Operations Center) construite avec FastAPI + Jinja2 + htmx,
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 | htmx (mises à jour partielles via JSON API) |
| Graphiques | Chart.js + ECharts |
| 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 dansbackend/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 SOCCLICKHOUSE_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_ipest de typeIPv4- Les tables ML (
ml_all_scores,ml_detected_anomalies) stockentIPv6(mappé::ffff:x.x.x.x) - Utiliser
toIPv6()pour les requêtes sur les tables ML - Utiliser
toIPv4OrZero()pour les requêtes surhttp_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 :
- Vue d'ensemble (
/) — identifier les tendances de menaces 24h, les pics d'anomalies - Détections (
/detections) — filtrer les anomalies par sévérité, rechercher des IPs spécifiques - Investigation IP (
/ip/{ip}) — examiner les détections, scores, logs HTTP, features ML, radar de comparaison - Analyse JA4 (
/ja4/{fp}) — investiguer une empreinte TLS, voir toutes les IPs associées - Campagnes (
/campaigns) — visualiser les clusters de bots, graphe réseau, scatter plot - Cluster (
/cluster/{cid}) — plonger dans un cluster spécifique, examiner les membres et profils - Flottes (
/fleet) — visualiser les communautés de botnets coordonnées (graphe bipartite JA4×ASN) - Tactiques (
/tactics) — surveiller le brute-force, la rotation JA4/UA, les menaces récurrentes - Classification (
/classify) — soumettre un feedback analyste (bot/légitime/suspect) pour alimenter XGBoost et le MetaLearner - Features (
/features) — comparer les profils de features humain vs bot - Modèles (
/models) — surveiller les performances des modèles ML - 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"}