Как стать автором
Обновить

ShieldPHP: многоуровневая защита от DDoS и брутфорс-атак для PHP-сайтов

Уровень сложностиСредний

ShieldPHP — это модульная система безопасности для веб-сайтов на PHP, которая обеспечивает многоуровневую защиту от различных типов атак, включая DDoS, брутфорс и сканирование уязвимостей. Рассмотрим её технические особенности и принципы работы.

Архитектура системы

Система состоит из нескольких ключевых компонентов:

  1. security_monitor.php — основной модуль мониторинга, отвечающий за обнаружение и блокировку подозрительной активности

  2. admin.php — административный интерфейс с панелью управления для настройки и мониторинга

  3. recaptcha_unlock.php — механизм разблокировки с использованием reCAPTCHA

  4. cleanup.php — фоновая служба для очистки устаревших данных и оптимизации

  5. settings.php — конфигурационный файл с настройками безопасности

  6. check_404.php — обработчик 404-ошибок для выявления сканирования

Система поддерживает работу с Redis и MariaDB, автоматически выбирая оптимальный режим в зависимости от доступности и настроек.

Методы обнаружения атак

1. Контроль частоты запросов

phpprivate function checkIPRateLimitRedis() {
    if (!$this->redis) return false;
    
    try {
        $key = $this->prefix . "ip_request_rate:{$this->ip}";
        $now = time();
        
        // Если ключ не существует, создаем его с TTL
        if (!$this->redis->exists($key)) {
            $ttl = defined('REDIS_TTL_IP_REQUEST_RATE') ? REDIS_TTL_IP_REQUEST_RATE : 600;
            
            $hashData = array(
                'request_count' => 1,
                'first_request_time' => $now,
                'last_request_time' => $now
            );
            
            $this->redis->hMSet($key, $hashData);
            $this->redis->expire($key, $ttl);
            
            return false;
        }
        
        // Увеличиваем счетчик запросов
        $this->redis->hIncrBy($key, 'request_count', 1);
        $this->redis->hSet($key, 'last_request_time', $now);
        
        // Проверяем превышение лимита
        $request_count = (int)$this->redis->hGet($key, 'request_count');
        $first_time = (int)$this->redis->hGet($key, 'first_request_time');
        $time_diff = $now - $first_time;
        
        $window = defined('RATE_CHECK_WINDOW') ? RATE_CHECK_WINDOW : 30;
        $threshold = defined('RATE_THRESHOLD') ? RATE_THRESHOLD : 20;
        
        // Если лимит запросов превышен во временном окне
        if ($time_diff <= $window && $request_count > $threshold) {
            return true;
        }
        
        return false;
    } catch (Exception $e) {
        error_log("Ошибка проверки лимита IP: " . $e->getMessage());
        return false;
    }
}
private function checkIPRateLimitRedis() {
    if (!$this->redis) return false;
    
    try {
        $key = $this->prefix . "ip_request_rate:{$this->ip}";
        $now = time();
        
        // Если ключ не существует, создаем его с TTL
        if (!$this->redis->exists($key)) {
            $ttl = defined('REDIS_TTL_IP_REQUEST_RATE') ? REDIS_TTL_IP_REQUEST_RATE : 600;
            
            $hashData = array(
                'request_count' => 1,
                'first_request_time' => $now,
                'last_request_time' => $now
            );
            
            $this->redis->hMSet($key, $hashData);
            $this->redis->expire($key, $ttl);
            
            return false;
        }
        
        // Увеличиваем счетчик запросов
        $this->redis->hIncrBy($key, 'request_count', 1);
        $this->redis->hSet($key, 'last_request_time', $now);
        
        // Проверяем превышение лимита
        $request_count = (int)$this->redis->hGet($key, 'request_count');
        $first_time = (int)$this->redis->hGet($key, 'first_request_time');
        $time_diff = $now - $first_time;
        
        $window = defined('RATE_CHECK_WINDOW') ? RATE_CHECK_WINDOW : 30;
        $threshold = defined('RATE_THRESHOLD') ? RATE_THRESHOLD : 20;
        
        // Если лимит запросов превышен во временном окне
        if ($time_diff <= $window && $request_count > $threshold) {
            return true;
        }
        
        return false;
    } catch (Exception $e) {
        error_log("Ошибка проверки лимита IP: " . $e->getMessage());
        return false;
    }
}

2. Анализ паттернов запросов

Система использует различные методики для выявления подозрительных паттернов:

  • Проверка временных интервалов между запросами Анализ дисперсии интервалов позволяет определить автоматические запросы

phpprivate function checkTimingDispersion() {
    // Вычисляем интервалы между запросами
    $intervals = array();
    $timings = $_SESSION['request_timings'];
    $count = count($timings);
    
    // Вычисляем средний интервал
    $avg = array_sum($intervals) / count($intervals);
    
    // Вычисляем дисперсию
    $variance = 0;
    foreach ($intervals as $interval) {
        $variance += pow($interval - $avg, 2);
    }
    $variance /= count($intervals);
    
    // Минимальная ожидаемая дисперсия для трафика человека
    $min_variance = defined('TIMING_DISPERSION_MIN') ? TIMING_DISPERSION_MIN : 0.2;
    
    // Если очень низкая дисперсия, вероятно, это бот
    if ($variance < $min_variance && $avg < 5) {
        return true;
    }
    
    return false;
}
private function checkTimingDispersion() {
    // Вычисляем интервалы между запросами
    $intervals = array();
    $timings = $_SESSION['request_timings'];
    $count = count($timings);
    
    // Вычисляем средний интервал
    $avg = array_sum($intervals) / count($intervals);
    
    // Вычисляем дисперсию
    $variance = 0;
    foreach ($intervals as $interval) {
        $variance += pow($interval - $avg, 2);
    }
    $variance /= count($intervals);
    
    // Минимальная ожидаемая дисперсия для трафика человека
    $min_variance = defined('TIMING_DISPERSION_MIN') ? TIMING_DISPERSION_MIN : 0.2;
    
    // Если очень низкая дисперсия, вероятно, это бот
    if ($variance < $min_variance && $avg < 5) {
        return true;
    }
    
    return false;
}
  • Обнаружение множественных User-Agent с одного IP Позволяет выявить имитацию разных браузеров

  • Проверка согласованности Cookie и сессий Обнаруживает попытки подмены сессий и манипуляции с Cookie

  • Honeypot URL мониторинг Отслеживание попыток доступа к несуществующим, но часто сканируемым путям

phpprivate function checkHoneypotUrl() {
    // Список URL, которые обычные пользователи никогда не посещают, но боты сканируют
    $honeypot_urls = array(
        '/wp-login.php',
        '/administrator/',
        '/admin.php',
        '/wp-admin/',
        '/xmlrpc.php',
        '/.env',
        // ... и другие часто сканируемые пути
    );
    
    // Проверяем текущий URL
    $current_url = $_SERVER['REQUEST_URI'];
    
    foreach ($honeypot_urls as $honeypot) {
        if (strpos($current_url, $honeypot) !== false) {
            // Дополнительная проверка на отсутствие cookies/referer
            if (empty($_COOKIE) || empty($_SERVER['HTTP_REFERER'])) {
                return true;
            }
        }
    }
    
    return false;
}
private function checkHoneypotUrl() {
    // Список URL, которые обычные пользователи никогда не посещают, но боты сканируют
    $honeypot_urls = array(
        '/wp-login.php',
        '/administrator/',
        '/admin.php',
        '/wp-admin/',
        '/xmlrpc.php',
        '/.env',
        // ... и другие часто сканируемые пути
    );
    
    // Проверяем текущий URL
    $current_url = $_SERVER['REQUEST_URI'];
    
    foreach ($honeypot_urls as $honeypot) {
        if (strpos($current_url, $honeypot) !== false) {
            // Дополнительная проверка на отсутствие cookies/referer
            if (empty($_COOKIE) || empty($_SERVER['HTTP_REFERER'])) {
                return true;
            }
        }
    }
    
    return false;
}

Механизмы блокировки

Система предлагает несколько уровней блокировки:

  1. Прогрессивная блокировка Повышение времени блокировки с каждым повторным нарушением

phpswitch ($block_count) {
    case 2:
        $progressive_seconds = defined('BLOCK_TIME_SECOND') ? BLOCK_TIME_SECOND : 10800; // 3 часа
        break;
    case 3:
        $progressive_seconds = defined('BLOCK_TIME_THIRD') ? BLOCK_TIME_THIRD : 21600; // 6 часов
        break;
    case 4:
        $progressive_seconds = defined('BLOCK_TIME_FOURTH') ? BLOCK_TIME_FOURTH : 43200; // 12 часов
        break;
    // ...и так далее
}
switch ($block_count) {
    case 2:
        $progressive_seconds = defined('BLOCK_TIME_SECOND') ? BLOCK_TIME_SECOND : 10800; // 3 часа
        break;
    case 3:
        $progressive_seconds = defined('BLOCK_TIME_THIRD') ? BLOCK_TIME_THIRD : 21600; // 6 часов
        break;
    case 4:
        $progressive_seconds = defined('BLOCK_TIME_FOURTH') ? BLOCK_TIME_FOURTH : 43200; // 12 часов
        break;
    // ...и так далее
}
  1. Многоуровневая защита Применение различных методов блокировки:

    • Redis и MariaDB для хранения состояния блокировок

    • .htaccess для блокировки на уровне веб-сервера

    • ip.conf для блокировки через Nginx

    • iptables/ip6tables для блокировки на уровне ОС

    • API для интеграции с внешними системами защиты

  2. Троттлинг (замедление) вместо блокировки Постепенное увеличение задержки для подозрительных IP:

phppublic function applyThrottling($requestType = 'default', $increase = true) {
    // Вычисляем задержку: чем больше превышение, тем дольше задержка
    $overLimit = $count - $limit;
    $delayFactor = min(1, $overLimit / $limit); // От 0 до 1
    $result['delay'] = (int)($maxDelay * $delayFactor);
    
    // Если настроено, применяем задержку
    if (defined('THROTTLING_APPLY_DELAY') && THROTTLING_APPLY_DELAY) {
        $this->applyDelay($result['delay']);
    }
}
public function applyThrottling($requestType = 'default', $increase = true) {
    // Вычисляем задержку: чем больше превышение, тем дольше задержка
    $overLimit = $count - $limit;
    $delayFactor = min(1, $overLimit / $limit); // От 0 до 1
    $result['delay'] = (int)($maxDelay * $delayFactor);
    
    // Если настроено, применяем задержку
    if (defined('THROTTLING_APPLY_DELAY') && THROTTLING_APPLY_DELAY) {
        $this->applyDelay($result['delay']);
    }
}
  1. Автоматическая жесткая блокировка При превышении порога блокировок активируется автоматическая жесткая блокировка для защиты от массированных атак

phpprivate function checkAndApplyAutoHardBlock() {
    // Определяем порог количества блокировок
    $threshold = defined('AUTO_HARD_BLOCK_THRESHOLD') ? AUTO_HARD_BLOCK_THRESHOLD : 100;
    
    // Получаем текущее количество заблокированных IP
    $blocked_count = $this->getBlockedIPsCount();
    
    // Если количество блокировок не превышает порог, выходим
    if ($blocked_count <= $threshold) {
        return false;
    }
    
    // Логируем событие
    error_log("Превышен порог количества заблокированных IP ($blocked_count > $threshold). Применяем жесткую блокировку.");
    
    // Получаем наиболее активные заблокированные IP
    $blocked_ips = $this->getMostActiveBlockedIPs(50);
    
    // Применяем жесткую блокировку
    $this->applyHardBlockToAll($blocked_ips);
    
    return true;
}
private function checkAndApplyAutoHardBlock() {
    // Определяем порог количества блокировок
    $threshold = defined('AUTO_HARD_BLOCK_THRESHOLD') ? AUTO_HARD_BLOCK_THRESHOLD : 100;
    
    // Получаем текущее количество заблокированных IP
    $blocked_count = $this->getBlockedIPsCount();
    
    // Если количество блокировок не превышает порог, выходим
    if ($blocked_count <= $threshold) {
        return false;
    }
    
    // Логируем событие
    error_log("Превышен порог количества заблокированных IP ($blocked_count > $threshold). Применяем жесткую блокировку.");
    
    // Получаем наиболее активные заблокированные IP
    $blocked_ips = $this->getMostActiveBlockedIPs(50);
    
    // Применяем жесткую блокировку
    $this->applyHardBlockToAll($blocked_ips);
    
    return true;
}

Система разблокировки

Для обеспечения возможности разблокировки легитимных пользователей система предоставляет механизм с использованием reCAPTCHA:

php// Проверка reCAPTCHA
public function verifyRecaptcha($recaptcha_response) {
    if (empty($recaptcha_response)) {
        return false;
    }
    
    $url = 'https://www.google.com/recaptcha/api/siteverify';
    $data = array(
        'secret' => RECAPTCHA_SECRET_KEY,
        'response' => $recaptcha_response,
        'remoteip' => $this->ip
    );
    
    $options = array(
        'http' => array(
            'header' => "Content-type: application/x-www-form-urlencoded\r\n",
            'method' => 'POST',
            'content' => http_build_query($data)
        )
    );
    
    $context = stream_context_create($options);
    $result = file_get_contents($url, false, $context);
    
    if ($result === FALSE) {
        return false;
    }
    
    $response = json_decode($result, true);
    return isset($response['success']) && $response['success'] === true;
}
// Проверка reCAPTCHA
public function verifyRecaptcha($recaptcha_response) {
    if (empty($recaptcha_response)) {
        return false;
    }
    
    $url = 'https://www.google.com/recaptcha/api/siteverify';
    $data = array(
        'secret' => RECAPTCHA_SECRET_KEY,
        'response' => $recaptcha_response,
        'remoteip' => $this->ip
    );
    
    $options = array(
        'http' => array(
            'header' => "Content-type: application/x-www-form-urlencoded\r\n",
            'method' => 'POST',
            'content' => http_build_query($data)
        )
    );
    
    $context = stream_context_create($options);
    $result = file_get_contents($url, false, $context);
    
    if ($result === FALSE) {
        return false;
    }
    
    $response = json_decode($result, true);
    return isset($response['success']) && $response['success'] === true;
}

Страница разблокировки также отслеживает частоту посещений для предотвращения атак на саму систему разблокировки.

Система администрирования

Административная панель предоставляет следующие возможности:

  1. Просмотр заблокированных IP-адресов и причин блокировки

  2. Управление белым списком для исключения определенных IP

  3. Мониторинг частоты запросов и подозрительной активности

  4. Очистка дублирующихся правил брандмауэра

  5. Оперативная разблокировка IP-адресов вручную

  6. Настройка режимов работы системы

Отказоустойчивость и производительность

Система обеспечивает высокую надежность благодаря:

  1. Многоуровневому кешированию Информация о блокировках хранится в Redis, MariaDB и файловом кеше для обеспечения доступности даже при сбоях

  2. Автоматическому переключению между Redis и MariaDB При недоступности Redis система автоматически переключается на MariaDB:

php// Если Redis недоступен, получаем данные из MariaDB
if (!$this->useRedis || !$this->redis) {
    // Пытаемся подключиться к БД
    $this->connectDB();
    $db_available = $this->db ? true : false;
    
    // Если БД доступна, используем её
    if ($db_available) {
        // Проверка через БД
        if ($this->checkIPRateLimitInDatabase()) {
            $this->logRequest();
            $this->blockIP(3600, 'Превышен лимит запросов');
            $this->redirectToUnlockPage();
            exit;
        }
    }
    // Если и база недоступна, используем файловый режим
    else if ($this->checkIPRateLimitFile()) {
        $this->applyDirectBlockings($this->ip);
        $this->redirectToUnlockPage();
        exit;
    }
}
// Если Redis недоступен, получаем данные из MariaDB
if (!$this->useRedis || !$this->redis) {
    // Пытаемся подключиться к БД
    $this->connectDB();
    $db_available = $this->db ? true : false;
    
    // Если БД доступна, используем её
    if ($db_available) {
        // Проверка через БД
        if ($this->checkIPRateLimitInDatabase()) {
            $this->logRequest();
            $this->blockIP(3600, 'Превышен лимит запросов');
            $this->redirectToUnlockPage();
            exit;
        }
    }
    // Если и база недоступна, используем файловый режим
    else if ($this->checkIPRateLimitFile()) {
        $this->applyDirectBlockings($this->ip);
        $this->redirectToUnlockPage();
        exit;
    }
}
  1. Оптимизации для высоконагруженных систем

    • Контроль использования памяти Redis

    • Периодическая очистка и оптимизация таблиц

    • Возможность настройки вероятностных проверок для снижения нагрузки

  2. Система уведомления администратора Автоматическое информирование о срабатывании защиты:

phpprivate function sendAdminNotification($total_blocked, $threshold) {
    // Формируем текст письма
    $message = "Внимание! На сайте $site_name активирована автоматическая жесткая блокировка.\n\n";
    $message .= "Порог активации: $threshold IP-адресов\n";
    $message .= "Текущее количество блокировок: $total_blocked IP-адресов\n";
    $message .= "Метод блокировки: " . (defined('AUTO_HARD_BLOCK_ACTION') ? 
                strtoupper(AUTO_HARD_BLOCK_ACTION) : 'ALL') . "\n\n";
    $message .= "Проверьте панель администратора для получения подробной информации.\n";
    
    // Отправляем письмо
    $mail_sent = @mail($admin_email, $subject, $message, $headers);
}
private function sendAdminNotification($total_blocked, $threshold) {
    // Формируем текст письма
    $message = "Внимание! На сайте $site_name активирована автоматическая жесткая блокировка.\n\n";
    $message .= "Порог активации: $threshold IP-адресов\n";
    $message .= "Текущее количество блокировок: $total_blocked IP-адресов\n";
    $message .= "Метод блокировки: " . (defined('AUTO_HARD_BLOCK_ACTION') ? 
                strtoupper(AUTO_HARD_BLOCK_ACTION) : 'ALL') . "\n\n";
    $message .= "Проверьте панель администратора для получения подробной информации.\n";
    
    // Отправляем письмо
    $mail_sent = @mail($admin_email, $subject, $message, $headers);
}

Установка и интеграция

Для установки системы необходимо:

  1. Скопировать все файлы в каталог /dos/ на вашем веб-сервере

  2. Настроить параметры в файле settings.php

  3. Добавить строку

    require_once $_SERVER['DOCUMENT_ROOT'] . '/dos/security_monitor.php';

    в начало главного файла сайта

  4. Создать таблицы в базе данных или запустить скрипт cleanup.php с параметром --create-tables

  5. Настроить периодический запуск cleanup.php через cron

    crontab -e
    */15 * * * * curl -s -A "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/121.0.0.0 Safari/537.36" https://mysite.com/dos/cleanup.php > /dev/null 2>&1
    

    Заключение

    ShieldPHP представляет собой комплексное решение для защиты веб-сайтов от различных типов атак. Благодаря многоуровневой архитектуре, система способна эффективно блокировать атаки даже при высокой нагрузке, обеспечивая при этом возможность легитимным пользователям разблокировать свои IP-адреса. Гибкая настройка и наличие административного интерфейса делают систему удобной в использовании для администраторов сайтов.

    Проект имеет открытый исходный код (лицензия MIT) и постоянно развивается. Подробная документация и инструкции по установке доступны на GitHub.

    Автор: Виталий Литвинов (murkir.pp.ua)

    Теги:
    Хабы:
    Данная статья не подлежит комментированию, поскольку её автор ещё не является полноправным участником сообщества. Вы сможете связаться с автором только после того, как он получит приглашение от кого-либо из участников сообщества. До этого момента его username будет скрыт псевдонимом.