Введение

Стандартные приложения и плагины-антиботы для Webasyst — это проверенные инструменты защиты, которые эффективно фильтруют трафик и блокируют нежелательных посетителей. Однако в их работе заложено фундаментальное ограничение: они активируются на этапе, когда фреймворк уже инициализировал соединение с базой данных. В условиях реальной массовой атаки, когда тысячи ботов одновременно обращаются к сайту, это становится критической уязвимостью — лимит MySQL-соединений исчерпывается и сервер выдает ошибку «Too many connections» еще до того, как защитный плагин успеет загрузиться.

Мы столкнулись с этой проблемой на практике, когда анализ логов выявил массированный перебор несуществующих страниц WordPress (/wp-admin/, xmlrpc.php) и поиск скрытых шелл-файлов. Поскольку архитектура Webasyst предполагает раннее подключение к БД, стандартные средства безопасности оказались бессильны предотвратить перегрузку. В данной статье я поделюсь опытом решения этой задачи через создание «раннего файрвола» на уровне SystemConfig.class.php. Этот метод позволяет блокировать вредоносные запросы на самом подлете, не допуская лишних обращений к базе данных и сохраняя работоспособность сайта даже под плотным огнем ботов.

Анализ проблемы

Из логов стали видны типичные атаки:

  • WordPress-сканеры: запросы к /wp-admin/, /wp-includes/, /xmlrpc.php
  • Перебор шеллов: txets.php, schallfuns.php, ioxi-o.php, xleet.php, rithin.php и десятки других
  • Сканеры конфигов: /.env, /.git/, /config.php
  • Обход директорий: ../, ..\\
  • Флуд главной страницы: множественные запросы к / за короткое время

Каждый такой запрос запускал полный цикл инициализации Webasyst, открывал соединение с MySQL и, при достижении лимита, вызывал ошибку Too many connections. Сайт становился недоступен.

Архитектурное ограничение Webasyst

Webasyst не предоставляет стандартных хуков для выполнения кода до инициализации базы данных. Плагины загружаются через механизм waAutoload и хуки приложений (routing, backend, и т.д.), но все они срабатывают после подключения к БД.

Однако существует официальный способ добавить свой код на самый ранний этап — через файл wa-config/SystemConfig.class.php, в котором можно переопределить метод init(). Согласно документации Webasyst, этот метод вызывается до подключения к базе данных, что делает его идеальным местом для раннего файрвола.

Решение: ранний файрвол

Мы создали файл wa-config/firewall.php, который содержит всю логику защиты, и подключили его из SystemConfig.class.php.

1. Структура файлов

wa-config/
├── SystemConfig.class.php    # Точка входа
├── firewall.php              # Логика файрвола
└── challenge.html            # Страница с JS-проверкой (опционально))

2. Точка входа (SystemConfig.class.php)

<?php

require_once dirname(__FILE__).'/../wa-system/autoload/waAutoload.class.php');
waAutoload::register();

require_once dirname(__FILE__) . '/firewall.php';

class SystemConfig extends waSystemConfig
{
    public function init()
    {
        Firewall::check();
        parent::init();
    }
}

3. Логика файрвола (firewall.php)

Файрвол работает в несколько этапов:

Этап 1: Проверка куки

Если у пользователя уже есть валидная кука (поставленная после успешного прохождения JS-проверки), он сразу пропускается к parent::init().

private static function hasValidCookie()
{
    $ip = $_SERVER['REMOTE_ADDR'] ?? '';
    
    if (!isset($_COOKIE[self::$cookie_name])) {
        return false;
    }
    
    $cookie_data = explode('_', $_COOKIE[self::$cookie_name]);
    if (count($cookie_data) !== 2) {
        return false;
    }
    
    return $cookie_data[1] === md5(self::$salt . $ip);
}

Этап 2: Грубая блокировка (earlyFirewall)

Блокировка по IP-адресам, плохим User-Agent и паттернам URI:

private static function earlyFirewall()
{
    // Блокировка по IP
    $bad_ips = ['20.48.254.119', '95.142.198.131', ...];
    
    // Блокировка по User-Agent (сканеры, инструменты, плохие боты)
    $bad_agents = ['curl', 'wget', 'python-requests', 'GPTBot', ...];
    
    // Блокировка по паттернам URI
    $patterns = [
        '/wp-admin/', '/wp-includes/', '/xmlrpc.php',
        'txets.php', 'schallfuns.php', '.tmb/cloud.php',
        '/.env', '/.git/', '/config.php', ...
    ];
}

Этап 3: JS-вызов (jsChallenge)

Для остальных запросов (нет куки, не заблокирован на предыдущих этапах) отправляется простая HTML-страница с JavaScript, который:

  1. Ставит куку
  2. Перезагружает страницу

Это отсекает ботов, которые не умеют выполнять JavaScript.

private static function jsChallenge()
{
    // Хорошие боты (поисковики, соцсети) пропускаются без проверки
    $good_bots = ['Googlebot', 'YandexBot', 'TelegramBot', ...];
    
    // Проверяем куку
    if (self::hasValidCookie()) {
        return;
    }
    
    // Отправляем JS-страницу
    self::showChallengePage($ip);
}

Этап 4: Страница с JS-проверкой

    <meta charset="UTF-8">
    <meta name="robots" content="noindex, nofollow">
    <title>Проверка браузера...</title>
    <style>
        body {
            background: #191e28;
            display: flex;
            justify-content: center;
            align-items: center;
            min-height: 100vh;
        }
        .spinner {
            border: 3px solid rgba(255,255,255,0.2);
            border-top-color: #d43f51;
            animation: spin 0.8s linear infinite;
        }
    </style>

    <div class="container">
        <div class="spinner"></div>
        <h2>Проверка браузера...</h2>
        <p>Пожалуйста, подождите.</p>
    </div>
    <script>
        document.cookie = "fw_verified={cookie_value}; path=/";
        location.reload();
    </script>

Результаты

После внедрения файрвола:

  • Блокировка вредоносных запросов происходит до подключения к БД
  • Ошибка Too many connections полностью исчезла
  • Нагрузка на сервер снизилась на ~70% для ботовых запросов
  • Реальные пользователи не замечают проверку (кука ставится один раз)

Итог

Ранний файрвол на уровне SystemConfig.class.php — это эффективное и архитектурно-корректное решение для защиты Webasyst-сайтов от ботов и атак, исчерпывающих соединения с базой данных. Оно не конфликтует с обновлениями фреймворка, легко расширяется и не требует сложной настройки.

Наш файрвол успешно решил проблему с ботами, которые создавали пиковые нагрузки на базу данных. Однако Too many connections может возникать и по другим причинам, не связанным с атаками.

Ключевые выводы

  1. Webasyst не имеет встроенного хука для ранней блокировки до подключения к БД
  2. SystemConfig.class.php — официальный способ добавить свой код на самый ранний этап
  3. JS-вызов эффективно отсекает ботов, не умеющих выполнять скрипты
  4. Белый список хороших ботов (Google, Яндекс, Telegram и др.) обеспечивает нормальную индексацию
  5. Чёрный список паттернов должен постоянно пополняться на основе анализа логов