<?php if (!defined('DASHBOARD_ROOT')) { http_response_code(403); exit; } class CanaryTokens { private const TRAP_ROUTES = [ '/wp-login.php' => 'wordpress_probe', '/wp-admin' => 'wordpress_probe', '/admin.php' => 'generic_admin_probe', '/phpmyadmin' => 'phpmyadmin_probe', '/administrator' => 'joomla_probe', '/.env' => 'env_exposure_probe', '/.git/config' => 'git_exposure_probe', '/xmlrpc.php' => 'xmlrpc_probe', '/wp-content' => 'wordpress_content_probe', '/config.php.bak' => 'backup_probe', ]; private const CANARY_API_KEY = 'ak_live_48fake72ce9b3d1a'; private const CANARY_ADMIN_USER = 'admin_support'; private const CANARY_CARD_PAN = '4111111111111111'; public static function checkRequest(string $uri): bool { $path = strtolower(parse_url($uri, PHP_URL_PATH) ?? ''); foreach (self::TRAP_ROUTES as $trap => $label) { if (strpos($path, $trap) !== false) { self::trigger('honeypot', $label, [ 'requested_path' => $path, 'full_uri' => substr($uri, 0, 500), ]); return true; } } return false; } public static function checkAPIKey(string $key): bool { if ($key === self::CANARY_API_KEY) { self::trigger('api_key', 'canary_key_used', [ 'key_submitted' => substr($key, 0, 20), ]); return true; } return false; } public static function checkAdminLogin(string $username): bool { if (strtolower($username) === self::CANARY_ADMIN_USER) { self::trigger('admin_acct', 'canary_admin_login', [ 'username_attempted' => $username, ]); return true; } return false; } public static function checkCardPAN(string $pan): bool { $clean = preg_replace('/[^0-9]/', '', $pan); if ($clean === self::CANARY_CARD_PAN) { self::trigger('test_card', 'canary_card_used', [ 'pan_prefix' => substr($clean, 0, 6), ]); return true; } return false; } private static function trigger(string $type, string $label, array $meta = []): void { $ip = $_SERVER['HTTP_X_REAL_IP'] ?? $_SERVER['REMOTE_ADDR'] ?? '0.0.0.0'; $ua = substr($_SERVER['HTTP_USER_AGENT'] ?? '', 0, 512); $meta['canary_type'] = $type; $meta['trigger_label'] = $label; $meta['ip'] = $ip; $meta['user_agent'] = $ua; $meta['triggered_at'] = date('Y-m-d H:i:s'); try { Events::record(Events::CAT_SECURITY, 'canary.' . $type, 'security', null, $meta); } catch (\Throwable $e) {} try { AuditLogger::log('canary.triggered', 'security', null, $meta); } catch (\Throwable $e) {} if (in_array($type, ['honeypot', 'admin_acct', 'test_card'])) { try { Database::execute( "INSERT IGNORE INTO blacklist (ip_address, reason, status_code, created_at)                      VALUES (:ip, :reason, 1, NOW())", [':ip' => $ip, ':reason' => 'canary_' . $type . ':' . $label] ); } catch (\Throwable $e) {} } } public static function recentTriggers(int $limit = 50): array { try { return Database::fetchAll( "SELECT id, action, meta, ip_address, created_at                  FROM events WHERE action LIKE 'canary.%'                  ORDER BY created_at DESC LIMIT :lim", [':lim' => $limit] ); } catch (\Throwable $e) { return []; } } public static function triggerCounts(int $hours = 24): array { try { return Database::fetchAll( "SELECT SUBSTRING(action, 8) as canary_type, COUNT(*) as trigger_count                  FROM events WHERE action LIKE 'canary.%'                  AND created_at > DATE_SUB(NOW(), INTERVAL :h HOUR)                  GROUP BY canary_type ORDER BY trigger_count DESC", [':h' => $hours] ); } catch (\Throwable $e) { return []; } } } 