Initial commit: Bot Detector Dashboard for SOC Incident Response
🛡️ Dashboard complet pour l'analyse et la classification des menaces Fonctionnalités principales: - Visualisation des détections en temps réel (24h) - Investigation multi-entités (IP, JA4, ASN, Host, User-Agent) - Analyse de corrélation pour classification SOC - Clustering automatique par subnet/JA4/UA - Export des classifications pour ML Composants: - Backend: FastAPI (Python) + ClickHouse - Frontend: React + TypeScript + TailwindCSS - 6 routes API: metrics, detections, variability, attributes, analysis, entities - 7 types d'entités investigables Documentation ajoutée: - NAVIGATION_GRAPH.md: Graph complet de navigation - SOC_OPTIMIZATION_PROPOSAL.md: Proposition d'optimisation pour SOC • Réduction de 7 à 2 clics pour classification • Nouvelle vue /incidents clusterisée • Panel latéral d'investigation • Quick Search (Cmd+K) • Timeline interactive • Graph de corrélations Sécurité: - .gitignore configuré (exclut .env, secrets, node_modules) - Credentials dans .env (à ne pas committer) ⚠️ Audit sécurité réalisé - Voir recommandations dans SOC_OPTIMIZATION_PROPOSAL.md Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
This commit is contained in:
122
backend/routes/metrics.py
Normal file
122
backend/routes/metrics.py
Normal file
@ -0,0 +1,122 @@
|
||||
"""
|
||||
Endpoints pour les métriques du dashboard
|
||||
"""
|
||||
from fastapi import APIRouter, HTTPException
|
||||
from ..database import db
|
||||
from ..models import MetricsResponse, MetricsSummary, TimeSeriesPoint
|
||||
|
||||
router = APIRouter(prefix="/api/metrics", tags=["metrics"])
|
||||
|
||||
|
||||
@router.get("", response_model=MetricsResponse)
|
||||
async def get_metrics():
|
||||
"""
|
||||
Récupère les métriques globales du dashboard
|
||||
"""
|
||||
try:
|
||||
# Résumé des métriques
|
||||
summary_query = """
|
||||
SELECT
|
||||
count() AS total_detections,
|
||||
countIf(threat_level = 'CRITICAL') AS critical_count,
|
||||
countIf(threat_level = 'HIGH') AS high_count,
|
||||
countIf(threat_level = 'MEDIUM') AS medium_count,
|
||||
countIf(threat_level = 'LOW') AS low_count,
|
||||
countIf(bot_name != '') AS known_bots_count,
|
||||
countIf(bot_name = '') AS anomalies_count,
|
||||
uniq(src_ip) AS unique_ips
|
||||
FROM ml_detected_anomalies
|
||||
WHERE detected_at >= now() - INTERVAL 24 HOUR
|
||||
"""
|
||||
|
||||
summary_result = db.query(summary_query)
|
||||
summary_row = summary_result.result_rows[0] if summary_result.result_rows else None
|
||||
|
||||
if not summary_row:
|
||||
raise HTTPException(status_code=404, detail="Aucune donnée disponible")
|
||||
|
||||
summary = MetricsSummary(
|
||||
total_detections=summary_row[0],
|
||||
critical_count=summary_row[1],
|
||||
high_count=summary_row[2],
|
||||
medium_count=summary_row[3],
|
||||
low_count=summary_row[4],
|
||||
known_bots_count=summary_row[5],
|
||||
anomalies_count=summary_row[6],
|
||||
unique_ips=summary_row[7]
|
||||
)
|
||||
|
||||
# Série temporelle (par heure)
|
||||
timeseries_query = """
|
||||
SELECT
|
||||
toStartOfHour(detected_at) AS hour,
|
||||
count() AS total,
|
||||
countIf(threat_level = 'CRITICAL') AS critical,
|
||||
countIf(threat_level = 'HIGH') AS high,
|
||||
countIf(threat_level = 'MEDIUM') AS medium,
|
||||
countIf(threat_level = 'LOW') AS low
|
||||
FROM ml_detected_anomalies
|
||||
WHERE detected_at >= now() - INTERVAL 24 HOUR
|
||||
GROUP BY hour
|
||||
ORDER BY hour
|
||||
"""
|
||||
|
||||
timeseries_result = db.query(timeseries_query)
|
||||
timeseries = [
|
||||
TimeSeriesPoint(
|
||||
hour=row[0],
|
||||
total=row[1],
|
||||
critical=row[2],
|
||||
high=row[3],
|
||||
medium=row[4],
|
||||
low=row[5]
|
||||
)
|
||||
for row in timeseries_result.result_rows
|
||||
]
|
||||
|
||||
# Distribution par menace
|
||||
threat_distribution = {
|
||||
"CRITICAL": summary.critical_count,
|
||||
"HIGH": summary.high_count,
|
||||
"MEDIUM": summary.medium_count,
|
||||
"LOW": summary.low_count
|
||||
}
|
||||
|
||||
return MetricsResponse(
|
||||
summary=summary,
|
||||
timeseries=timeseries,
|
||||
threat_distribution=threat_distribution
|
||||
)
|
||||
|
||||
except Exception as e:
|
||||
raise HTTPException(status_code=500, detail=f"Erreur lors de la récupération des métriques: {str(e)}")
|
||||
|
||||
|
||||
@router.get("/threats")
|
||||
async def get_threat_distribution():
|
||||
"""
|
||||
Récupère la répartition par niveau de menace
|
||||
"""
|
||||
try:
|
||||
query = """
|
||||
SELECT
|
||||
threat_level,
|
||||
count() AS count,
|
||||
round(count() * 100.0 / sum(count()) OVER (), 2) AS percentage
|
||||
FROM ml_detected_anomalies
|
||||
WHERE detected_at >= now() - INTERVAL 24 HOUR
|
||||
GROUP BY threat_level
|
||||
ORDER BY count DESC
|
||||
"""
|
||||
|
||||
result = db.query(query)
|
||||
|
||||
return {
|
||||
"items": [
|
||||
{"threat_level": row[0], "count": row[1], "percentage": row[2]}
|
||||
for row in result.result_rows
|
||||
]
|
||||
}
|
||||
|
||||
except Exception as e:
|
||||
raise HTTPException(status_code=500, detail=f"Erreur: {str(e)}")
|
||||
Reference in New Issue
Block a user