feat: ja4-platform monorepo — 5 services unified, tests & RPM builds standardized
Services: - ja4sentinel: TLS/JA4 fingerprint capture daemon (Go, libpcap) - logcorrelator: JA4 log correlation engine (Go, ClickHouse) - mod_reqin_log: Apache module (C, JSON request logging) - bot_detector: ML bot detection pipeline (Python) - dashboard: FastAPI/Streamlit analytics UI (Python) Shared libraries: - shared/go/ja4common: logger, config, shutdown, ipfilter (Go module) - shared/python/ja4_common: ClickHouseClient, ClickHouseSettings (Python package) - shared/clickhouse/: canonical SQL migrations (10 files) Build & packaging: - Unified 3-stage Dockerfile.package for Go RPMs (el8/el9/el10) - go.work workspace linking sentinel, correlator, ja4common - Makefile with test-all, build-all, rpm-* targets Fixes applied: - go.work: 1.21 → 1.24.6 (required by sentinel) - correlator Dockerfiles: golang:1.21 → golang:1.24 - replace directives in go.mod for ja4common local path - pyproject.toml: setuptools.backends → setuptools.build_meta - Removed static libpcap linking (unavailable on Rocky 9) - Fixed data races in output/writers_test.go (sync.Mutex + atomic.Int32) - Rewrote corrupted test files (logger_test.go × 2) Test coverage: - correlator: 67.1% total (unixsocket 80.5%, config 91.7%, app 83.3%, multi 87.7%, stdout 100%) - sentinel: all 10 packages pass (api, capture, config, fingerprint, ipfilter, logging, output, tlsparse) Documentation: - README.md + docs/ (architecture, development, 5 services, shared libs, DB schema & migrations) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
672
services/dashboard/README.md
Normal file
672
services/dashboard/README.md
Normal file
@ -0,0 +1,672 @@
|
||||
# 🛡️ Bot Detector Dashboard
|
||||
|
||||
Dashboard web interactif pour visualiser et investiguer les décisions de classification du Bot Detector IA.
|
||||
|
||||
**Version:** 2.0.0 - TCP Fingerprinting Multi-Signal + Clustering IPs Multi-Métriques
|
||||
|
||||
## 🚀 Démarrage Rapide
|
||||
|
||||
### Prérequis
|
||||
|
||||
- Docker et Docker Compose
|
||||
- Le service `clickhouse` déjà déployé
|
||||
- Des données dans la table `ml_detected_anomalies`
|
||||
- Des données dans la table `http_logs` (pour les user-agents)
|
||||
|
||||
> **Note:** Le dashboard peut fonctionner indépendamment de `bot_detector_ai`. Il lit les données déjà détectées dans ClickHouse.
|
||||
|
||||
### Lancement
|
||||
|
||||
```bash
|
||||
# 1. Vérifier que .env existe
|
||||
cp .env.example .env # Si ce n'est pas déjà fait
|
||||
|
||||
# 2. Lancer le dashboard (avec Docker Compose v2)
|
||||
docker compose up -d dashboard_web
|
||||
|
||||
# Ou avec l'ancienne syntaxe
|
||||
docker-compose up -d dashboard_web
|
||||
|
||||
# 3. Ouvrir le dashboard
|
||||
# http://localhost:3000
|
||||
```
|
||||
|
||||
### Arrêt
|
||||
|
||||
```bash
|
||||
docker compose stop dashboard_web
|
||||
```
|
||||
|
||||
### Vérifier le statut
|
||||
|
||||
```bash
|
||||
# Voir les services en cours d'exécution
|
||||
docker compose ps
|
||||
|
||||
# Voir les logs en temps réel
|
||||
docker compose logs -f dashboard_web
|
||||
```
|
||||
|
||||
## 📊 Fonctionnalités
|
||||
|
||||
### Dashboard Principal
|
||||
- **Métriques en temps réel** : Total détections, menaces, bots connus, IPs uniques
|
||||
- **Comparaison baseline J-1** : variation ▲▼ vs hier (détections, IPs uniques, CRITICAL)
|
||||
- **Répartition par menace** : Visualisation CRITICAL/HIGH/MEDIUM/LOW
|
||||
- **Évolution temporelle** : Graphique des détections sur 24h
|
||||
- **Incidents clusterisés** : Regroupement automatique par subnet /24
|
||||
- **Top Menaces Actives** : Top 10 des IPs les plus dangereuses
|
||||
|
||||
### 🧬 TCP Spoofing & Fingerprinting OS (amélioré v2.0)
|
||||
- **Détection multi-signal** : TTL initial + MSS + scale + fenêtre TCP (p0f-style)
|
||||
- **20 signatures OS** : Linux, Windows, macOS, Android, iOS, Masscan, ZMap, Shodan, Googlebot…
|
||||
- **Estimation hop-count** : différence TTL initial (arrondi) − TTL observé
|
||||
- **Détection réseau** : MSS → Ethernet (1460) / PPPoE (1452) / VPN (1420) / Tunnel (<1420)
|
||||
- **Confiance 0–100%** : score pondéré (TTL 40% + MSS 30% + fenêtre 20% + scale 10%)
|
||||
- **Badge bot-tool** : Masscan détecté à 97% (win=5808, mss=1452, scale=4)
|
||||
- **Distribution MSS** : histogramme des MSS observés par cluster
|
||||
|
||||
### 🔬 Clustering IPs Multi-Métriques (nouveau v2.0)
|
||||
- **URL:** `/clustering`
|
||||
- **Algorithme :** K-means++ (Arthur & Vassilvitskii, 2007), initialisé avec k-means++, 3 runs
|
||||
- **21 features normalisées [0,1] :**
|
||||
- Stack TCP : TTL initial, MSS, scale, fenêtre TCP
|
||||
- Anomalie ML : score, vélocité, fuzzing, headless, POST ratio, IP-ID zéro
|
||||
- TLS/Protocole : ALPN mismatch, ALPN absent, efficacité H2 (multiplexing)
|
||||
- Navigateur : score navigateur moderne, ordre headers, UA-CH mismatch
|
||||
- Temporel : entropie, diversité JA4, UA rotatif
|
||||
- **Positionnement 2D :** PCA par puissance itérative (Hotelling) + déflation
|
||||
- **Nommage automatique :** Masscan / Bot UA Rotatif / Bot Fuzzer / Anomalie ML / Linux / Windows / VPN
|
||||
|
||||
**Vue Tableau de bord (défaut) :**
|
||||
- Grille de cartes groupées : Bots confirmés → Suspects → Légitimes
|
||||
- Chaque carte : label, IP count, hits, badge CRITIQUE/ÉLEVÉ/MODÉRÉ/SAIN
|
||||
- 4 mini-barres : anomalie, UA-CH mismatch, fuzzing, UA rotatif
|
||||
- Stack TCP (TTL, MSS, Scale), top pays, ASN
|
||||
|
||||
**Vue Graphe de relations :**
|
||||
- Nœuds-cartes ReactFlow (220px, texte lisible)
|
||||
- Colonnes par niveau de menace : Bots | Suspects | Légitimes
|
||||
- Arêtes colorées par similarité (orange=fort, animé=très fort)
|
||||
- Légende intégrée, minimap, contrôles zoom
|
||||
|
||||
**Sidebar de détail :**
|
||||
- RadarChart comportemental (10 axes : anomalie, UA-CH, fuzzing, headless…)
|
||||
- Toutes les métriques avec barres de progression colorées
|
||||
- Liste des IPs avec badges menace/pays/ASN
|
||||
- Export **Copier IPs** + **⬇ CSV**
|
||||
|
||||
### Investigation Subnet /24
|
||||
- **URL:** `/entities/subnet/x.x.x.x_24`
|
||||
- Stats globales, tableau des IPs, actions par IP
|
||||
|
||||
### Investigation IP + Réputation
|
||||
- **URL:** `/investigation/:ip`
|
||||
- Synthèse multi-sources (ML + bruteforce + TCP + JA4 + timeline)
|
||||
- Score de risque 0–100, réputation IP-API + IPinfo
|
||||
|
||||
### Investigation (Variabilité)
|
||||
- User-Agents, JA4 fingerprints, pays, ASN, hosts, niveaux de menace
|
||||
- Insights automatiques, navigation enchaînable
|
||||
|
||||
## 🏗️ Architecture
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────┐
|
||||
│ Docker Compose │
|
||||
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────────┐ │
|
||||
│ │ ClickHouse │ │ bot_detector│ │ dashboard_web │ │
|
||||
│ │ :8123 │ │ (existant) │ │ :8000 (web+API)│ │
|
||||
│ │ :9000 │ │ │ │ network=host │ │
|
||||
│ └──────┬──────┘ └──────┬──────┘ └────────┬────────┘ │
|
||||
│ └────────────────┴───────────────────┘ │
|
||||
└─────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
> Le container utilise `network_mode: "host"` — le frontend buildé est servi par FastAPI
|
||||
> sur le **port 8000 uniquement** (pas de port 3000 en production).
|
||||
|
||||
### Composants
|
||||
|
||||
| Composant | Technologie | Description |
|
||||
|-----------|-------------|-------------|
|
||||
| **Frontend** | React 18 + TypeScript 5 + Vite 5 + Tailwind CSS 3 | Interface utilisateur (SPA) |
|
||||
| **Backend API** | FastAPI 0.111 + Python 3.11 | API REST + serveur statique SPA |
|
||||
| **Database** | ClickHouse (existant) — port 8123 | Base de données principale |
|
||||
| **Clustering** | K-means++ pur Python + PCA puissance itérative | Algorithmes embarqués, sans dépendance ML |
|
||||
|
||||
## 📁 Structure
|
||||
|
||||
```
|
||||
dashboard/
|
||||
├── Dockerfile # Multi-stage: node:20-alpine → python:3.11-slim
|
||||
├── docker-compose.yaml
|
||||
├── requirements.txt
|
||||
├── backend/
|
||||
│ ├── main.py # FastAPI: CORS, routers, SPA catch-all (doit être DERNIER)
|
||||
│ ├── config.py # pydantic-settings, lit .env
|
||||
│ ├── database.py # ClickHouseClient singleton (db)
|
||||
│ ├── models.py # Modèles Pydantic v2
|
||||
│ ├── routes/
|
||||
│ │ ├── metrics.py # GET /api/metrics, /api/metrics/baseline
|
||||
│ │ ├── detections.py # GET /api/detections
|
||||
│ │ ├── variability.py # GET /api/variability
|
||||
│ │ ├── attributes.py # GET /api/attributes
|
||||
│ │ ├── incidents.py # GET /api/incidents/clusters
|
||||
│ │ ├── entities.py # GET /api/entities
|
||||
│ │ ├── analysis.py # GET/POST /api/analysis — classifications SOC
|
||||
│ │ ├── reputation.py # GET /api/reputation/ip/{ip}
|
||||
│ │ ├── tcp_spoofing.py # GET /api/tcp-spoofing — fingerprinting OS multi-signal
|
||||
│ │ ├── clustering.py # GET /api/clustering/clusters + /cluster/{id}/ips
|
||||
│ │ └── investigation_summary.py # GET /api/investigation/{ip}/summary
|
||||
│ └── services/
|
||||
│ ├── tcp_fingerprint.py # 20 signatures OS, scoring, hop-count, réseau path
|
||||
│ ├── clustering_engine.py # K-means++, PCA-2D, nommage, score risque (pur Python)
|
||||
│ └── reputation_ip.py # httpx → ip-api.com + ipinfo.io (async, sans API key)
|
||||
└── frontend/
|
||||
├── package.json
|
||||
├── vite.config.ts # Proxy /api → :8000 en dev
|
||||
└── src/
|
||||
├── App.tsx # BrowserRouter + Sidebar + TopHeader + Routes
|
||||
├── ThemeContext.tsx # dark/light/auto, localStorage: soc_theme
|
||||
├── api/client.ts # Axios baseURL=/api + toutes les interfaces TypeScript
|
||||
├── components/
|
||||
│ ├── ClusteringView.tsx # K-means++ clustering — 2 vues
|
||||
│ ├── TcpSpoofingView.tsx # TCP fingerprinting OS
|
||||
│ ├── InvestigationView.tsx # Investigation IP complète
|
||||
│ └── ... # Autres vues
|
||||
├── hooks/ # useMetrics, useDetections, useVariability (polling)
|
||||
└── utils/STIXExporter.ts
|
||||
```
|
||||
|
||||
## 🔌 API
|
||||
|
||||
### Endpoints
|
||||
|
||||
| Method | Endpoint | Description |
|
||||
|--------|----------|-------------|
|
||||
| GET | `/api/metrics` | Métriques globales |
|
||||
| GET | `/api/metrics/baseline` | Comparaison J-1 (détections, IPs, CRITICAL) |
|
||||
| GET | `/api/metrics/threats` | Distribution par menace |
|
||||
| GET | `/api/detections` | Liste des détections paginée |
|
||||
| GET | `/api/detections/{id}` | Détails d'une détection |
|
||||
| GET | `/api/variability/{type}/{value}` | Variabilité d'un attribut |
|
||||
| GET | `/api/attributes/{type}` | Valeurs uniques d'un attribut |
|
||||
| GET | `/api/incidents/clusters` | Incidents clusterisés par subnet /24 |
|
||||
| GET | `/api/entities/subnet/{subnet}` | Investigation subnet (ex: `141.98.11.0_24`) |
|
||||
| GET | `/api/entities/{type}/{value}` | Investigation entité (IP, JA4, UA…) |
|
||||
| GET | `/api/reputation/ip/{ip}` | Réputation IP (IP-API + IPinfo) |
|
||||
| GET | `/api/investigation/{ip}/summary` | Synthèse IP multi-sources (ML + TCP + JA4) |
|
||||
| GET | `/api/analysis/{ip}/subnet` | Analyse subnet / ASN |
|
||||
| GET | `/api/analysis/{ip}/recommendation` | Recommandation de classification |
|
||||
| POST | `/api/analysis/classifications` | Sauvegarder classification SOC |
|
||||
| GET | `/api/tcp-spoofing/overview` | Vue d'ensemble TCP spoofing + OS |
|
||||
| GET | `/api/tcp-spoofing/list` | Liste des détections TCP spoofing |
|
||||
| GET | `/api/tcp-spoofing/matrix` | Matrice OS déclaré vs OS réel |
|
||||
| GET | `/api/clustering/clusters` | Clustering K-means++ (`?k=14&n_samples=3000`) |
|
||||
| GET | `/api/clustering/cluster/{id}/ips` | IPs d'un cluster (drill-down) |
|
||||
| GET | `/health` | Health check |
|
||||
|
||||
### Exemples
|
||||
|
||||
```bash
|
||||
# Health check
|
||||
curl http://localhost:8000/health
|
||||
|
||||
# Métriques globales + baseline
|
||||
curl http://localhost:8000/api/metrics | jq '.summary'
|
||||
curl http://localhost:8000/api/metrics/baseline | jq
|
||||
|
||||
# Détections CRITICAL
|
||||
curl "http://localhost:8000/api/detections?threat_level=CRITICAL&page=1" | jq '.items | length'
|
||||
|
||||
# TCP Spoofing — vue d'ensemble
|
||||
curl http://localhost:8000/api/tcp-spoofing/overview | jq
|
||||
|
||||
# Clustering IPs (14 clusters sur 3000 échantillons)
|
||||
curl "http://localhost:8000/api/clustering/clusters?k=14&n_samples=3000" | jq '.stats'
|
||||
|
||||
# Drill-down d'un cluster
|
||||
curl "http://localhost:8000/api/clustering/cluster/c0_k14/ips?limit=20" | jq '.ips[].ip'
|
||||
|
||||
# Réputation IP
|
||||
curl http://localhost:8000/api/reputation/ip/162.55.94.175 | jq
|
||||
```
|
||||
|
||||
## ⚙️ Configuration
|
||||
|
||||
### Variables d'Environnement
|
||||
|
||||
| Variable | Défaut | Description |
|
||||
|----------|--------|-------------|
|
||||
| `CLICKHOUSE_HOST` | `clickhouse` | Hôte ClickHouse |
|
||||
| `CLICKHOUSE_PORT` | `8123` | Port HTTP ClickHouse |
|
||||
| `CLICKHOUSE_DB` | `mabase_prod` | Base de données |
|
||||
| `CLICKHOUSE_USER` | `admin` | Utilisateur |
|
||||
| `CLICKHOUSE_PASSWORD` | `` | Mot de passe |
|
||||
| `API_HOST` | `0.0.0.0` | Bind Uvicorn |
|
||||
| `API_PORT` | `8000` | Port API + frontend |
|
||||
| `CORS_ORIGINS` | `["http://localhost:3000", ...]` | Origines CORS autorisées |
|
||||
|
||||
Ces variables sont lues depuis le fichier `.env` à la racine du projet.
|
||||
|
||||
> ⚠️ Le fichier `.env` contient les credentials réels — ne jamais le committer.
|
||||
|
||||
## 🔍 Workflows d'Investigation
|
||||
|
||||
### Exemple 1 : Identifier un bot Masscan
|
||||
|
||||
1. **🔬 Clustering IPs** → Cluster "🤖 Masscan / Scanner IP" visible en rouge
|
||||
2. **Clic sur la carte** → Sidebar : TTL=52, MSS=1452, Scale=4 — pattern Masscan
|
||||
3. **Copier les IPs** → Liste prête pour le blocage
|
||||
4. **Export CSV** → Import dans le SIEM ou firewall
|
||||
|
||||
### Exemple 2 : Analyser des bots UA-rotatifs (cloud)
|
||||
|
||||
1. **Clustering** → Cluster "🤖 Bot UA Rotatif + CH Mismatch" (risque 50%)
|
||||
2. **RadarChart** → UA-CH=100%, UA rotatif=100%, anomalie=59%
|
||||
3. **Top ASN** → Microsoft, Google, Akamai — cloud providers
|
||||
4. **🧬 TCP Spoofing** → Confirmer : ces IPs déclarent Windows UA mais ont TTL Linux
|
||||
5. **Investigation IP** → Détail complet avec timeline 24h
|
||||
|
||||
### Exemple 3 : Détecter le spoofing d'OS
|
||||
|
||||
1. **🧬 TCP Spoofing** → Liste des IPs avec mismatch OS
|
||||
2. **Matrice UA×OS** → User-Agent Android mais stack TCP Windows = spoof
|
||||
3. **Confiance 85%** → MSS=1460 (Ethernet), scale=7, TTL≈64 → Linux réel
|
||||
4. **Action** → Classer comme bot avec IP proxy
|
||||
|
||||
### Exemple 4 : Investiguer une IP suspecte
|
||||
|
||||
1. **🎯 Détections** → IP classifiée 🔴 CRITICAL
|
||||
2. **Clic sur l'IP** → Synthèse : ML + TCP + JA4 + bruteforce + timeline
|
||||
3. **Score de risque** : 85/100
|
||||
4. **User-Agents** → 3 UA différents en 24h (rotation)
|
||||
5. **TCP** → TTL initial 128 (Windows) mais UA Linux → spoof
|
||||
6. **Action** → Blacklist immédiate
|
||||
|
||||
## 🧬 Services techniques (v2.0)
|
||||
|
||||
### `backend/services/tcp_fingerprint.py`
|
||||
|
||||
Détection multi-signal de l'OS réel basée sur la stack TCP :
|
||||
|
||||
```python
|
||||
from backend.services.tcp_fingerprint import fingerprint_os, detect_spoof
|
||||
|
||||
result = fingerprint_os(ttl=52, win=5808, scale=4, mss=1452)
|
||||
# → OSFingerprint(os_family="Masscan/Scanner", confidence=0.97, is_bot_tool=True)
|
||||
|
||||
spoof = detect_spoof(declared_ua="Chrome/Windows", fingerprint=result)
|
||||
# → SpoofResult(is_spoof=True, reason="UA Windows mais stack Masscan", risk_score=30)
|
||||
```
|
||||
|
||||
**Poids du scoring :** TTL initial 40% + MSS 30% + fenêtre 20% + scale 10%
|
||||
|
||||
**Estimation hop-count :**
|
||||
- TTL observé 52 → TTL initial arrondi = 64 → hops = 64 − 52 = **12**
|
||||
- TTL observé 119 → TTL initial = 128 → hops = 9
|
||||
|
||||
**MSS → chemin réseau :**
|
||||
| MSS | Réseau détecté |
|
||||
|-----|---------------|
|
||||
| 1460 | Ethernet standard |
|
||||
| 1452 | PPPoE / DSL |
|
||||
| 1420–1452 | VPN probable |
|
||||
| < 1420 | Tunnel / double-encap |
|
||||
|
||||
### `backend/services/clustering_engine.py`
|
||||
|
||||
K-means++ + PCA-2D embarqués en pur Python (sans numpy/sklearn) :
|
||||
|
||||
```
|
||||
K-means++ init : O(k·n) distances, n_init=3 runs → meilleure inertie
|
||||
Power iteration : X^T(Xv) trick → O(n·d) par itération, pas de matrice n×n
|
||||
Déflation Hotelling : retire PC1 de X avant de calculer PC2
|
||||
```
|
||||
|
||||
**21 features normalisées [0,1]** — voir `FEATURES` dans le fichier.
|
||||
|
||||
**Nommage automatique** par priorité décroissante :
|
||||
1. Pattern Masscan (mss 1440–1460, scale 3–5, TTL<60)
|
||||
2. Fuzzing agressif (fuzzing_index normalisé > 0.35 ≈ valeur brute > 100)
|
||||
3. UA rotatif + UA-CH mismatch simultanés
|
||||
4. UA-CH mismatch seul > 80%
|
||||
5. Score anomalie ML > 20% + signal comportemental
|
||||
6. Classification réseau / OS par TTL/MSS
|
||||
|
||||
## 🗄️ Tables ClickHouse utilisées
|
||||
|
||||
| Table / Vue | Routes |
|
||||
|---|---|
|
||||
| `mabase_prod.ml_detected_anomalies` | metrics, detections, variability, analysis, clustering |
|
||||
| `mabase_prod.agg_host_ip_ja4_1h` | tcp_spoofing, clustering, investigation_summary |
|
||||
| `mabase_prod.view_dashboard_entities` | entities (UA, JA4, paths, query params) |
|
||||
| `mabase_prod.classifications` | analysis (classifications SOC manuelles) |
|
||||
| `mabase_prod.audit_logs` | audit (optionnel — silencieux si absent) |
|
||||
|
||||
**Conventions SQL :**
|
||||
- IPs stockées en IPv6-mappé : `replaceRegexpAll(toString(src_ip), '^::ffff:', '')`
|
||||
- `anomaly_score` peut être négatif : toujours utiliser `abs()`
|
||||
- `fuzzing_index` peut dépasser 200 : normaliser avec `log1p`
|
||||
- `multiplexing_efficiency` peut dépasser 1 : normaliser avec `log1p`
|
||||
- Paramètres SQL : syntaxe `%(name)s` (dict ClickHouse)
|
||||
- **SPA catch-all DOIT être le dernier router dans `main.py`**
|
||||
|
||||
## 🎨 Thème
|
||||
|
||||
Le dashboard utilise un **thème sombre** optimisé SOC (dark par défaut, clair et auto disponibles) :
|
||||
|
||||
- **Tokens CSS sémantiques** : `bg-background`, `bg-background-card`, `text-text-primary`, `text-text-secondary`…
|
||||
- **Taxonomie menaces** : rouge CRITICAL / orange HIGH / jaune MEDIUM / vert LOW
|
||||
- **Persistance** : `localStorage` clé `soc_theme`
|
||||
- **Ne jamais utiliser** de classes Tailwind brutes (`slate-800`) — toujours les tokens sémantiques
|
||||
|
||||
## 📝 Logs
|
||||
|
||||
Les logs du dashboard sont accessibles via Docker :
|
||||
|
||||
```bash
|
||||
# Logs du container
|
||||
docker logs dashboard_web
|
||||
|
||||
# Logs en temps réel
|
||||
docker logs -f dashboard_web
|
||||
```
|
||||
|
||||
## 🧪 Tests et Validation
|
||||
|
||||
### Script de test rapide
|
||||
|
||||
Créez un fichier `test_dashboard.sh` :
|
||||
|
||||
```bash
|
||||
#!/bin/bash
|
||||
echo "=== Test Dashboard Bot Detector ==="
|
||||
|
||||
# 1. Health check
|
||||
echo -n "1. Health check... "
|
||||
curl -s http://localhost:3000/health > /dev/null && echo "✅ OK" || echo "❌ ÉCHOUÉ"
|
||||
|
||||
# 2. API Metrics
|
||||
echo -n "2. API Metrics... "
|
||||
curl -s http://localhost:3000/api/metrics | jq -e '.summary' > /dev/null && echo "✅ OK" || echo "❌ ÉCHOUÉ"
|
||||
|
||||
# 3. API Detections
|
||||
echo -n "3. API Detections... "
|
||||
curl -s http://localhost:3000/api/detections | jq -e '.items' > /dev/null && echo "✅ OK" || echo "❌ ÉCHOUÉ"
|
||||
|
||||
# 4. Frontend
|
||||
echo -n "4. Frontend HTML... "
|
||||
curl -s http://localhost:3000 | grep -q "Bot Detector" && echo "✅ OK" || echo "❌ ÉCHOUÉ"
|
||||
|
||||
echo "=== Tests terminés ==="
|
||||
```
|
||||
|
||||
Rendez-le exécutable et lancez-le :
|
||||
|
||||
```bash
|
||||
chmod +x test_dashboard.sh
|
||||
./test_dashboard.sh
|
||||
```
|
||||
|
||||
### Tests manuels de l'API
|
||||
|
||||
```bash
|
||||
# 1. Health check
|
||||
curl http://localhost:3000/health
|
||||
|
||||
# 2. Métriques globales
|
||||
curl http://localhost:3000/api/metrics | jq
|
||||
|
||||
# 3. Liste des détections (page 1, 25 items)
|
||||
curl "http://localhost:3000/api/detections?page=1&page_size=25" | jq
|
||||
|
||||
# 4. Filtrer par menace CRITICAL
|
||||
curl "http://localhost:3000/api/detections?threat_level=CRITICAL" | jq '.items[].src_ip'
|
||||
|
||||
# 5. Distribution par menace
|
||||
curl http://localhost:3000/api/metrics/threats | jq
|
||||
|
||||
# 6. Liste des IPs uniques (top 10)
|
||||
curl "http://localhost:3000/api/attributes/ip?limit=10" | jq
|
||||
|
||||
# 7. Variabilité d'une IP (remplacer par une IP réelle)
|
||||
curl http://localhost:3000/api/variability/ip/192.168.1.100 | jq
|
||||
|
||||
# 8. Variabilité d'un pays
|
||||
curl http://localhost:3000/api/variability/country/FR | jq
|
||||
|
||||
# 9. Variabilité d'un ASN
|
||||
curl http://localhost:3000/api/variability/asn/16276 | jq
|
||||
```
|
||||
|
||||
### Test du Frontend
|
||||
|
||||
```bash
|
||||
# Vérifier que le HTML est servi
|
||||
curl -s http://localhost:3000 | head -20
|
||||
|
||||
# Ou ouvrir dans le navigateur
|
||||
# http://localhost:3000
|
||||
```
|
||||
|
||||
### Scénarios de test utilisateur
|
||||
|
||||
1. **Navigation de base**
|
||||
- Ouvrir http://localhost:3000
|
||||
- Vérifier que les métriques s'affichent
|
||||
- Cliquer sur "📋 Détections"
|
||||
|
||||
2. **Recherche et filtres**
|
||||
- Rechercher une IP : `192.168`
|
||||
- Filtrer par menace : CRITICAL
|
||||
- Changer de page
|
||||
|
||||
3. **Investigation (variabilité)**
|
||||
- Cliquer sur une IP dans le tableau
|
||||
- Vérifier la section "User-Agents" (plusieurs valeurs ?)
|
||||
- Cliquer sur un User-Agent pour investiguer
|
||||
- Utiliser le breadcrumb pour revenir en arrière
|
||||
|
||||
4. **Insights**
|
||||
- Trouver une IP avec plusieurs User-Agents
|
||||
- Vérifier que l'insight "Possible rotation/obfuscation" s'affiche
|
||||
|
||||
### Vérifier les données ClickHouse
|
||||
|
||||
```bash
|
||||
# Compter les détections (24h)
|
||||
docker compose exec clickhouse clickhouse-client -d mabase_prod -q \
|
||||
"SELECT count() FROM ml_detected_anomalies WHERE detected_at >= now() - INTERVAL 24 HOUR"
|
||||
|
||||
# Voir un échantillon
|
||||
docker compose exec clickhouse clickhouse-client -d mabase_prod -q \
|
||||
"SELECT src_ip, threat_level, model_name, detected_at FROM ml_detected_anomalies ORDER BY detected_at DESC LIMIT 5"
|
||||
|
||||
# Vérifier les vues du dashboard
|
||||
docker compose exec clickhouse clickhouse-client -d mabase_prod -q \
|
||||
"SELECT * FROM view_dashboard_summary"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🐛 Dépannage
|
||||
|
||||
### Diagnostic rapide
|
||||
|
||||
```bash
|
||||
# 1. Vérifier que les services tournent
|
||||
docker compose ps
|
||||
|
||||
# 2. Vérifier les logs du dashboard
|
||||
docker compose logs dashboard_web | tail -50
|
||||
|
||||
# 3. Tester la connexion ClickHouse depuis le dashboard
|
||||
docker compose exec dashboard_web curl -v http://clickhouse:8123/ping
|
||||
```
|
||||
|
||||
### Le dashboard ne démarre pas
|
||||
|
||||
```bash
|
||||
# Vérifier les logs
|
||||
docker compose logs dashboard_web
|
||||
|
||||
# Erreur courante: Port déjà utilisé
|
||||
# Solution: Changer le port dans docker-compose.yml
|
||||
|
||||
# Erreur courante: Image non construite
|
||||
docker compose build dashboard_web
|
||||
docker compose up -d dashboard_web
|
||||
```
|
||||
|
||||
### Aucune donnée affichée (dashboard vide)
|
||||
|
||||
```bash
|
||||
# 1. Vérifier qu'il y a des données dans ClickHouse
|
||||
docker compose exec clickhouse clickhouse-client -d mabase_prod -q \
|
||||
"SELECT count() FROM ml_detected_anomalies WHERE detected_at >= now() - INTERVAL 24 HOUR"
|
||||
|
||||
# Si le résultat est 0:
|
||||
# - Lancer bot_detector_ai pour générer des données
|
||||
docker compose up -d bot_detector_ai
|
||||
docker compose logs -f bot_detector_ai
|
||||
|
||||
# - Ou importer des données manuellement
|
||||
```
|
||||
|
||||
### Erreur "Connexion ClickHouse échoué"
|
||||
|
||||
```bash
|
||||
# 1. Vérifier que ClickHouse est démarré
|
||||
docker compose ps clickhouse
|
||||
|
||||
# 2. Tester la connexion
|
||||
docker compose exec clickhouse clickhouse-client -q "SELECT 1"
|
||||
|
||||
# 3. Vérifier les credentials dans .env
|
||||
cat .env | grep CLICKHOUSE
|
||||
|
||||
# 4. Redémarrer le dashboard
|
||||
docker compose restart dashboard_web
|
||||
|
||||
# 5. Vérifier les logs d'erreur
|
||||
docker compose logs dashboard_web | grep -i error
|
||||
```
|
||||
|
||||
### Erreur 404 sur les routes API
|
||||
|
||||
```bash
|
||||
# Vérifier que l'API répond
|
||||
curl http://localhost:3000/health
|
||||
curl http://localhost:3000/api/metrics
|
||||
|
||||
# Si 404, redémarrer le dashboard
|
||||
docker compose restart dashboard_web
|
||||
```
|
||||
|
||||
### Port 3000 déjà utilisé
|
||||
|
||||
```bash
|
||||
# Option 1: Changer le port dans docker-compose.yml
|
||||
# Remplacer: - "3000:8000"
|
||||
# Par: - "8080:8000"
|
||||
|
||||
# Option 2: Trouver et tuer le processus
|
||||
lsof -i :3000
|
||||
kill <PID>
|
||||
|
||||
# Puis redémarrer
|
||||
docker compose up -d dashboard_web
|
||||
```
|
||||
|
||||
### Frontend ne se charge pas (page blanche)
|
||||
|
||||
```bash
|
||||
# 1. Vérifier la console du navigateur (F12)
|
||||
# 2. Vérifier que le build frontend existe
|
||||
docker compose exec dashboard_web ls -la /app/frontend/dist
|
||||
|
||||
# 3. Si vide, reconstruire l'image
|
||||
docker compose build --no-cache dashboard_web
|
||||
docker compose up -d dashboard_web
|
||||
```
|
||||
|
||||
### Logs d'erreur courants
|
||||
|
||||
| Erreur | Cause | Solution |
|
||||
|--------|-------|----------|
|
||||
| `Connection refused` | ClickHouse pas démarré | `docker compose up -d clickhouse` |
|
||||
| `Authentication failed` | Mauvais credentials | Vérifier `.env` |
|
||||
| `Table doesn't exist` | Vues non créées | Lancer `deploy_views.sql` |
|
||||
| `No data available` | Pas de données | Lancer `bot_detector_ai` |
|
||||
|
||||
---
|
||||
|
||||
## 🔒 Sécurité
|
||||
|
||||
- **Pas d'authentification** : Dashboard conçu pour un usage local
|
||||
- **CORS restreint** : Seulement localhost:3000
|
||||
- **Rate limiting** : 100 requêtes/minute
|
||||
- **Credentials** : Via variables d'environnement (jamais en dur)
|
||||
|
||||
## 📊 Performances
|
||||
|
||||
- **Temps de chargement** : < 2s (avec données)
|
||||
- **Requêtes ClickHouse** : Optimisées avec agrégations
|
||||
- **Rafraîchissement auto** : 30 secondes (métriques)
|
||||
|
||||
## 🧪 Développement
|
||||
|
||||
### Build local (sans Docker)
|
||||
|
||||
```bash
|
||||
# Backend
|
||||
cd dashboard
|
||||
pip install -r requirements.txt
|
||||
python -m uvicorn backend.main:app --reload --host 0.0.0.0 --port 8000
|
||||
|
||||
# Frontend (dans un autre terminal)
|
||||
cd dashboard/frontend
|
||||
npm install
|
||||
npm run dev # http://localhost:5173
|
||||
```
|
||||
|
||||
### Documentation API interactive
|
||||
|
||||
L'API inclut une documentation Swagger interactive :
|
||||
|
||||
```bash
|
||||
# Ouvrir dans le navigateur
|
||||
http://localhost:3000/docs
|
||||
|
||||
# Ou directement sur le port API
|
||||
http://localhost:8000/docs
|
||||
```
|
||||
|
||||
### Tests unitaires (à venir)
|
||||
|
||||
```bash
|
||||
# Backend (pytest)
|
||||
cd dashboard
|
||||
pytest backend/tests/
|
||||
|
||||
# Frontend (jest)
|
||||
cd dashboard/frontend
|
||||
npm test
|
||||
```
|
||||
|
||||
## 📄 License
|
||||
|
||||
Même license que le projet principal Bot Detector.
|
||||
|
||||
---
|
||||
|
||||
## 📞 Support
|
||||
|
||||
Pour toute question ou problème :
|
||||
|
||||
1. Vérifier la section **🐛 Dépannage** ci-dessus
|
||||
2. Consulter les logs : `docker compose logs dashboard_web`
|
||||
3. Vérifier que ClickHouse contient des données
|
||||
4. Ouvrir une issue sur le dépôt
|
||||
Reference in New Issue
Block a user