false, 'message' => '']; switch ($_POST['action']) { case 'block_ip': $ip = escapeshellarg($_POST['ip'] ?? ''); if ($ip) { exec("fail2ban-client set sshd banip " . trim($_POST['ip'], "'") . " 2>&1", $output, $code); $result = ['success' => $code === 0, 'message' => $code === 0 ? "IP bloquée" : "Échec"]; } break; case 'kill_query': case 'kill_connection': $pid = intval($_POST['pid'] ?? 0); if ($pid > 0) { try { $pdo = new PDO("pgsql:host=127.0.0.1;port=5432;dbname=adx_system", 'admin', 'admin123'); $stmt = $pdo->prepare("SELECT pg_terminate_backend(?)"); $stmt->execute([$pid]); $result = ['success' => true, 'message' => "Connexion #{$pid} terminée"]; } catch (Exception $e) { $result = ['success' => false, 'message' => $e->getMessage()]; } } break; case 'block_db_ip': $ip = escapeshellarg($_POST['ip'] ?? ''); if ($ip) { exec("iptables -A INPUT -s {$ip} -p tcp --dport 5432 -j DROP 2>&1", $output, $code); $result = ['success' => $code === 0, 'message' => $code === 0 ? "IP bloquée de la DB" : "Échec"]; } break; case 'vacuum_table': $table = preg_replace('/[^a-zA-Z0-9_]/', '', $_POST['table'] ?? ''); if ($table) { try { $pdo = new PDO("pgsql:host=127.0.0.1;port=5432;dbname=adx_system", 'admin', 'admin123'); $pdo->exec("VACUUM ANALYZE {$table}"); $result = ['success' => true, 'message' => "VACUUM {$table} OK"]; } catch (Exception $e) { $result = ['success' => false, 'message' => $e->getMessage()]; } } break; case 'vacuum_full': $table = preg_replace('/[^a-zA-Z0-9_]/', '', $_POST['table'] ?? ''); if ($table) { exec("sudo -u postgres psql -d adx_system -c \"VACUUM FULL {$table}\" 2>&1", $output, $code); $result = ['success' => $code === 0, 'message' => $code === 0 ? "VACUUM FULL {$table} OK" : implode("\n", $output)]; } break; case 'analyze_table': $table = preg_replace('/[^a-zA-Z0-9_]/', '', $_POST['table'] ?? ''); if ($table) { try { $pdo = new PDO("pgsql:host=127.0.0.1;port=5432;dbname=adx_system", 'admin', 'admin123'); $pdo->exec("ANALYZE {$table}"); $result = ['success' => true, 'message' => "ANALYZE {$table} OK"]; } catch (Exception $e) { $result = ['success' => false, 'message' => $e->getMessage()]; } } break; case 'reindex_table': $table = preg_replace('/[^a-zA-Z0-9_]/', '', $_POST['table'] ?? ''); if ($table) { exec("sudo -u postgres psql -d adx_system -c \"REINDEX TABLE {$table}\" 2>&1", $output, $code); $result = ['success' => $code === 0, 'message' => $code === 0 ? "REINDEX {$table} OK" : implode("\n", $output)]; } break; case 'cancel_query': $pid = intval($_POST['pid'] ?? 0); if ($pid > 0) { try { $pdo = new PDO("pgsql:host=127.0.0.1;port=5432;dbname=adx_system", 'admin', 'admin123'); $stmt = $pdo->prepare("SELECT pg_cancel_backend(?)"); $stmt->execute([$pid]); $result = ['success' => true, 'message' => "Requête #{$pid} annulée"]; } catch (Exception $e) { $result = ['success' => false, 'message' => $e->getMessage()]; } } break; case 'clear_idle_connections': try { $pdo = new PDO("pgsql:host=127.0.0.1;port=5432;dbname=adx_system", 'admin', 'admin123'); $stmt = $pdo->query("SELECT pg_terminate_backend(pid) FROM pg_stat_activity WHERE state = 'idle' AND pid <> pg_backend_pid() AND query_start < NOW() - INTERVAL '10 minutes'"); $count = $stmt->rowCount(); $result = ['success' => true, 'message' => "{$count} connexion(s) fermée(s)"]; } catch (Exception $e) { $result = ['success' => false, 'message' => $e->getMessage()]; } break; case 'reset_stats': try { $pdo = new PDO("pgsql:host=127.0.0.1;port=5432;dbname=adx_system", 'admin', 'admin123'); $pdo->exec("SELECT pg_stat_reset()"); $result = ['success' => true, 'message' => "Stats remises à zéro"]; } catch (Exception $e) { $result = ['success' => false, 'message' => $e->getMessage()]; } break; case 'ignore_ip': $ip = $_POST['ip'] ?? ''; if ($ip && !in_array($ip, $_SESSION['ignored_ips'])) { $_SESSION['ignored_ips'][] = $ip; $result = ['success' => true, 'message' => "IP {$ip} ignorée"]; } break; case 'whitelist_ip': $ip = $_POST['ip'] ?? ''; if ($ip && filter_var($ip, FILTER_VALIDATE_IP)) { @mkdir('/opt/wevads/config', 0755, true); $current = file_exists($whitelist_file) ? file_get_contents($whitelist_file) : ''; if (strpos($current, $ip) === false) { file_put_contents($whitelist_file, $ip . "\n", FILE_APPEND); $result = ['success' => true, 'message' => "IP {$ip} autorisée"]; } else { $result = ['success' => true, 'message' => "IP déjà autorisée"]; } } break; case 'clear_ignored': $_SESSION['ignored_ips'] = []; $result = ['success' => true, 'message' => 'IPs ignorées effacées']; break; } echo json_encode($result); exit; } $effective_allowed_ips = $allowed_db_ips; function getDatabaseStats() { global $effective_allowed_ips, $allowed_db_users, $sensitive_tables; $ignored_ips = $_SESSION['ignored_ips'] ?? []; $stats = ['connected' => false, 'connections' => ['active' => 0, 'idle' => 0, 'idle_in_transaction' => 0, 'max' => 100, 'total' => 0], 'cache_hit_ratio' => 0, 'databases' => [], 'tables' => [], 'slow_queries' => [], 'active_queries' => [], 'locks' => 0, 'waiting_locks' => [], 'uptime' => 'N/A', 'transactions' => 0, 'intrusion_alerts' => [], 'recent_connections' => [], 'long_running' => [], 'idle_connections' => 0]; try { $pdo = new PDO("pgsql:host=127.0.0.1;port=5432;dbname=adx_system", 'admin', 'admin123', [PDO::ATTR_TIMEOUT => 5]); $stats['connected'] = true; // Intrusion alerts $stmt = $pdo->query("SELECT pid, usename, client_addr, datname, state, query FROM pg_stat_activity WHERE client_addr IS NOT NULL AND client_addr::text NOT IN ('127.0.0.1', '::1')"); while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) { $ip = $row['client_addr']; if (!in_array($ip, $effective_allowed_ips) && !in_array($ip, $ignored_ips)) { $stats['intrusion_alerts'][] = ['type' => 'EXTERNAL_CONNECTION', 'severity' => 'CRITICAL', 'title' => 'Connexion externe', 'description' => "IP {$ip} connectée comme '{$row['usename']}'", 'pid' => $row['pid'], 'source_ip' => $ip]; } } // Connections $stmt = $pdo->query("SELECT pid, usename, client_addr, datname, application_name, backend_start, state, query, EXTRACT(EPOCH FROM (NOW() - backend_start))::int as duration FROM pg_stat_activity WHERE backend_type = 'client backend' ORDER BY backend_start DESC LIMIT 25"); while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) { $row['is_trusted'] = in_array($row['client_addr'], $effective_allowed_ips) || in_array($row['client_addr'], $ignored_ips) || $row['client_addr'] === null; $row['is_ignored'] = in_array($row['client_addr'], $ignored_ips); $stats['recent_connections'][] = $row; } $stmt = $pdo->query("SELECT state, count(*) as cnt FROM pg_stat_activity GROUP BY state"); while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) { if ($row['state'] === 'active') $stats['connections']['active'] = $row['cnt']; elseif ($row['state'] === 'idle') $stats['connections']['idle'] = $row['cnt']; elseif ($row['state'] === 'idle in transaction') $stats['connections']['idle_in_transaction'] = $row['cnt']; } $stmt = $pdo->query("SELECT count(*) as cnt FROM pg_stat_activity WHERE state = 'idle' AND query_start < NOW() - INTERVAL '10 minutes'"); $stats['idle_connections'] = $stmt->fetch(PDO::FETCH_ASSOC)['cnt'] ?? 0; $stmt = $pdo->query("SELECT count(*) as total FROM pg_stat_activity"); $stats['connections']['total'] = $stmt->fetch(PDO::FETCH_ASSOC)['total']; $stmt = $pdo->query("SHOW max_connections"); $stats['connections']['max'] = $stmt->fetch(PDO::FETCH_ASSOC)['max_connections'] ?? 100; $stmt = $pdo->query("SELECT ROUND(sum(blks_hit) * 100.0 / NULLIF(sum(blks_hit) + sum(blks_read), 0), 2) as ratio FROM pg_stat_database"); $stats['cache_hit_ratio'] = $stmt->fetch(PDO::FETCH_ASSOC)['ratio'] ?? 0; $stmt = $pdo->query("SELECT datname, pg_size_pretty(pg_database_size(datname)) as size FROM pg_database WHERE datname NOT LIKE 'template%' ORDER BY pg_database_size(datname) DESC LIMIT 5"); $stats['databases'] = $stmt->fetchAll(PDO::FETCH_ASSOC); $stmt = $pdo->query("SELECT relname as name, n_live_tup as rows, n_dead_tup as dead, pg_size_pretty(pg_total_relation_size(relid)) as size, last_vacuum, last_autovacuum, last_analyze FROM pg_stat_user_tables ORDER BY n_live_tup DESC LIMIT 15"); $stats['tables'] = $stmt->fetchAll(PDO::FETCH_ASSOC); $stmt = $pdo->query("SELECT pid, usename, client_addr, datname, state, EXTRACT(EPOCH FROM (NOW() - query_start))::int as duration, LEFT(query, 100) as query FROM pg_stat_activity WHERE state = 'active' AND query NOT LIKE '%pg_stat_activity%' ORDER BY query_start LIMIT 15"); $stats['active_queries'] = $stmt->fetchAll(PDO::FETCH_ASSOC); $stmt = $pdo->query("SELECT pid, usename, client_addr, datname, EXTRACT(EPOCH FROM (NOW() - query_start))::int as duration, LEFT(query, 150) as query FROM pg_stat_activity WHERE state = 'active' AND NOW() - query_start > interval '5 seconds' AND query NOT LIKE '%pg_stat_activity%' ORDER BY duration DESC LIMIT 10"); $stats['slow_queries'] = $stmt->fetchAll(PDO::FETCH_ASSOC); $stmt = $pdo->query("SELECT pid, usename, client_addr, datname, state, EXTRACT(EPOCH FROM (NOW() - query_start))::int as duration, LEFT(query, 150) as query FROM pg_stat_activity WHERE NOW() - query_start > interval '1 minute' AND query NOT LIKE '%pg_stat_activity%' AND state != 'idle' ORDER BY duration DESC LIMIT 5"); $stats['long_running'] = $stmt->fetchAll(PDO::FETCH_ASSOC); $stmt = $pdo->query("SELECT bl.pid as blocked_pid, a.usename as blocked_user, kl.pid as blocking_pid, ka.usename as blocking_user, a.query as blocked_query FROM pg_catalog.pg_locks bl JOIN pg_catalog.pg_stat_activity a ON a.pid = bl.pid JOIN pg_catalog.pg_locks kl ON kl.transactionid = bl.transactionid AND kl.pid != bl.pid JOIN pg_catalog.pg_stat_activity ka ON ka.pid = kl.pid WHERE NOT bl.granted LIMIT 10"); $stats['waiting_locks'] = $stmt->fetchAll(PDO::FETCH_ASSOC); $stats['locks'] = count($stats['waiting_locks']); $stmt = $pdo->query("SELECT NOW() - pg_postmaster_start_time() as uptime"); $stats['uptime'] = $stmt->fetch(PDO::FETCH_ASSOC)['uptime'] ?? 'N/A'; $stmt = $pdo->query("SELECT sum(xact_commit + xact_rollback) as total FROM pg_stat_database"); $stats['transactions'] = $stmt->fetch(PDO::FETCH_ASSOC)['total'] ?? 0; } catch (Exception $e) { $stats['error'] = $e->getMessage(); } return $stats; } function getSecurityReport() { global $effective_allowed_ips; $ignored_ips = $_SESSION['ignored_ips'] ?? []; $report = ['status' => 'secure', 'score' => 100, 'checks' => [], 'threats' => [], 'timestamp' => date('Y-m-d H:i:s')]; $known_ips = $GLOBALS["allowed_db_ips"]; try { $pdo = new PDO("pgsql:host=127.0.0.1;port=5432;dbname=adx_system", 'admin', 'admin123', [PDO::ATTR_TIMEOUT => 5]); $stmt = $pdo->query("SELECT pid, usename, client_addr, query FROM pg_stat_activity WHERE state != 'idle' AND query NOT LIKE '%pg_stat_activity%'"); $suspicious = []; while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) { if (preg_match('/(DROP|DELETE FROM|TRUNCATE|pg_dump|COPY.*TO)/i', $row['query'])) { $suspicious[] = $row; $report['threats'][] = ['type' => 'DATABASE', 'severity' => 'CRITICAL', 'title' => 'Requête suspecte', 'description' => substr($row['query'], 0, 100), 'source' => $row['client_addr'] ?: 'local', 'pid' => $row['pid']]; } } if (count($suspicious) > 0) { $report['status'] = 'critical'; $report['score'] -= 40; } $report['checks'][] = ['name' => 'Requêtes DB', 'status' => count($suspicious) == 0 ? 'ok' : 'failed', 'detail' => count($suspicious) == 0 ? 'OK' : count($suspicious) . ' suspecte(s)']; } catch (Exception $e) { $report['checks'][] = ['name' => 'Requêtes DB', 'status' => 'warning', 'detail' => 'Non vérifiable']; } $ssh_output = shell_exec("who 2>/dev/null"); $unknown_ssh = []; if ($ssh_output) { preg_match_all('/\(([0-9.]+)\)/', $ssh_output, $matches); foreach ($matches[1] as $ip) { if (!in_array($ip, $known_ips)) { $unknown_ssh[] = $ip; $report['threats'][] = ['type' => 'SSH', 'severity' => 'HIGH', 'title' => 'Connexion SSH inconnue', 'description' => $ip, 'source' => $ip]; } } } if (count($unknown_ssh) > 0) { $report['score'] -= 20; if ($report['status'] === 'secure') $report['status'] = 'warning'; } $report['checks'][] = ['name' => 'Sessions SSH', 'status' => count($unknown_ssh) == 0 ? 'ok' : 'warning', 'detail' => count($unknown_ssh) == 0 ? 'OK' : count($unknown_ssh) . ' inconnue(s)']; $failed = shell_exec("grep 'Failed password' /var/log/auth.log 2>/dev/null | tail -100 | awk '{print \$(NF-3)}' | sort | uniq -c | sort -rn | head -5"); $brute = []; if ($failed) { foreach (array_filter(explode("\n", trim($failed))) as $line) { if (preg_match('/^\s*(\d+)\s+(.+)$/', $line, $m) && intval($m[1]) >= 10 && !in_array($m[2], $ignored_ips)) { $brute[] = $m[2]; $report['threats'][] = ['type' => 'BRUTE_FORCE', 'severity' => 'HIGH', 'title' => 'Attaque force brute', 'description' => "{$m[1]} tentatives depuis {$m[2]}", 'source' => $m[2]]; } } } if (count($brute) > 0) { $report['score'] -= 25; if ($report['status'] === 'secure') $report['status'] = 'warning'; } $report['checks'][] = ['name' => 'Force brute', 'status' => count($brute) == 0 ? 'ok' : 'warning', 'detail' => count($brute) == 0 ? 'OK' : count($brute) . ' attaque(s)']; $malware = shell_exec("ps aux | grep -E '(cryptominer|xmrig|minerd)' | grep -v grep"); if (!empty(trim($malware ?? ''))) { $report['status'] = 'critical'; $report['score'] -= 50; } $report['checks'][] = ['name' => 'Malware', 'status' => empty(trim($malware ?? '')) ? 'ok' : 'failed', 'detail' => empty(trim($malware ?? '')) ? 'Aucun' : 'Détecté!']; $disk = intval(shell_exec("df -h / | tail -1 | awk '{print \$5}' | tr -d '%'")); if ($disk > 90) $report['score'] -= 15; $report['checks'][] = ['name' => 'Disque', 'status' => $disk <= 90 ? 'ok' : 'warning', 'detail' => "{$disk}%"]; $fw = intval(shell_exec("iptables -L -n 2>/dev/null | wc -l")); $report['checks'][] = ['name' => 'Pare-feu', 'status' => $fw > 10 ? 'ok' : 'warning', 'detail' => $fw > 10 ? 'Actif' : 'Limité']; $f2b = trim(shell_exec("systemctl is-active fail2ban 2>/dev/null")) === 'active'; $report['checks'][] = ['name' => 'Fail2Ban', 'status' => $f2b ? 'ok' : 'warning', 'detail' => $f2b ? 'Actif' : 'Inactif']; if (!$f2b) $report['score'] -= 5; if ($report['score'] < 50) $report['status'] = 'critical'; elseif ($report['score'] < 80) $report['status'] = 'warning'; $report['score'] = max(0, $report['score']); return $report; } $report = getSecurityReport(); $db_stats = getDatabaseStats(); if (!empty($db_stats['intrusion_alerts'])) { $critical_db = count(array_filter($db_stats['intrusion_alerts'], fn($a) => $a['severity'] === 'CRITICAL')); if ($critical_db > 0) { $report['status'] = 'critical'; $report['score'] = max(0, $report['score'] - ($critical_db * 20)); } } $is_current_ip_whitelisted = in_array($current_ip, $effective_allowed_ips); $is_current_ip_ignored = false; ?> 🛡️ Sécurité WEVAL

Rapport de Sécurité

Retour

Cette page surveille la sécurité de votre serveur et base de données. Score 100 = parfait. Actualisation auto: 30 sec.

Votre IP
Rouge = Danger
Orange = Attention
Vert = OK
Bleu = Vous
0): ?>
IP(s) ignorée(s):
/ 100
Sécurisé Attention Critique
Vérifications
🚨 Alertes intrusion ()
⚠️
Connexions suspectes
Des IPs inconnues accèdent à la DB. Si c'est vous (VPN), autorisez. Sinon, bloquez.
🔴 CRITIQUE
Menaces ()
👤 VOUS
Whitelist
Base PostgreSQL
Uptime:
Actions rapides
5): ?>
⚠️
Trop de connexions inactives
connexions dorment depuis +10 min.
🔒
Blocage détecté
requête(s) bloquée(s).
🐢
Requêtes longues (> 1 min)
requête(s) trop lente(s).
Connexions ()
PIDUserIPBaseÉtatDuréeActions
VOUS' : '' ?>m
Connexions
80 ? 'bad' : ($conn_pct > 50 ? 'warn' : 'good'); ?>
Actives
Inactives
Total / Max /
Performance
= 95 ? 'good' : ($db_stats['cache_hit_ratio'] >= 90 ? 'warn' : 'bad'); ?>
Cache Hit%
Transactions
Verrous
Taille bases
Requêtes lentes (> 5s)
PIDUserDuréeRequêteActions
s
Requêtes actives
PIDUserBaseDuréeRequêteActions
s
Tables
Actions: 🧹 VACUUM | 📦 VACUUM FULL (⚠️ bloque!) | 📊 ANALYZE | 📑 REINDEX
10000; ?>
TableTailleLignesDeadDernier VACUUMÉtatActions
⚠️ VACUUM' : '✓ OK' ?>
PostgreSQL non connecté
// ========== API CHECK IP SECURITY ========== if (isset($_GET['action']) && $_GET['action'] === 'check_ip') { header('Content-Type: application/json'); $currentIP = $_SERVER['HTTP_X_FORWARDED_FOR'] ?? $_SERVER['HTTP_X_REAL_IP'] ?? $_SERVER['REMOTE_ADDR'] ?? 'unknown'; if (strpos($currentIP, ',') !== false) { $currentIP = trim(explode(',', $currentIP)[0]); } // IPs connues/whitelistées (ajoute tes IPs habituelles ici) $knownIPs = [ '89.167.40.150', // Hetzner prod '151.80.235.110', // OVH '46.62.241.15', // Nouveau serveur // Ajoute tes IPs personnelles ici