ShieldPHP: многоуровневая защита от DDoS и брутфорс-атак для PHP-сайтов
ShieldPHP — это модульная система безопасности для веб-сайтов на PHP, которая обеспечивает многоуровневую защиту от различных типов атак, включая DDoS, брутфорс и сканирование уязвимостей. Рассмотрим её технические особенности и принципы работы.
Архитектура системы
Система состоит из нескольких ключевых компонентов:
security_monitor.php — основной модуль мониторинга, отвечающий за обнаружение и блокировку подозрительной активности
admin.php — административный интерфейс с панелью управления для настройки и мониторинга
recaptcha_unlock.php — механизм разблокировки с использованием reCAPTCHA
cleanup.php — фоновая служба для очистки устаревших данных и оптимизации
settings.php — конфигурационный файл с настройками безопасности
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;
}
Механизмы блокировки
Система предлагает несколько уровней блокировки:
Прогрессивная блокировка Повышение времени блокировки с каждым повторным нарушением
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;
// ...и так далее
}
Многоуровневая защита Применение различных методов блокировки:
Redis и MariaDB для хранения состояния блокировок
.htaccess для блокировки на уровне веб-сервера
ip.conf для блокировки через Nginx
iptables/ip6tables для блокировки на уровне ОС
API для интеграции с внешними системами защиты
Троттлинг (замедление) вместо блокировки Постепенное увеличение задержки для подозрительных 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']);
}
}
Автоматическая жесткая блокировка При превышении порога блокировок активируется автоматическая жесткая блокировка для защиты от массированных атак
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;
}
Страница разблокировки также отслеживает частоту посещений для предотвращения атак на саму систему разблокировки.
Система администрирования
Административная панель предоставляет следующие возможности:
Просмотр заблокированных IP-адресов и причин блокировки
Управление белым списком для исключения определенных IP
Мониторинг частоты запросов и подозрительной активности
Очистка дублирующихся правил брандмауэра
Оперативная разблокировка IP-адресов вручную
Настройка режимов работы системы
Отказоустойчивость и производительность
Система обеспечивает высокую надежность благодаря:
Многоуровневому кешированию Информация о блокировках хранится в Redis, MariaDB и файловом кеше для обеспечения доступности даже при сбоях
Автоматическому переключению между 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;
}
}
Оптимизации для высоконагруженных систем
Контроль использования памяти Redis
Периодическая очистка и оптимизация таблиц
Возможность настройки вероятностных проверок для снижения нагрузки
Система уведомления администратора Автоматическое информирование о срабатывании защиты:
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);
}
Установка и интеграция
Для установки системы необходимо:
Скопировать все файлы в каталог
/dos/
на вашем веб-сервереНастроить параметры в файле
settings.php
Добавить строку
require_once $_SERVER['DOCUMENT_ROOT'] . '/dos/security_monitor.php';
в начало главного файла сайта
Создать таблицы в базе данных или запустить скрипт
cleanup.php
с параметром--create-tables
Настроить периодический запуск
cleanup.php
через croncrontab -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)