# 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](bot-detector.md). 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 ```python 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 : ```html
``` 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` : ```python 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 ```bash # 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"} ```