Вчера вечером я просмотрел свою аналитику и увидел тысячи посетителей, время ожидания администратора истекло, а процессор моего сервера резко увеличился. После того, как я уже сражался и пресекал атаки в прошлом квартале, я начал устранять неполадки и нашел виновника: Внутренний поиск WordPress.

Боковое примечание: Похоже, рост Martech Zone кого-то действительно бесит! Не знаю, чем я заслужил такое внимание, но да…

Злоумышленники и агрессивные боты часто используют поисковую систему WordPress по умолчанию для запуска Атака на истощение ресурсов. Это тип атаки типа «отказ в обслуживании» (DoS) на уровне приложения, предназначенной не для кражи данных, а для перегрузки сервера базы данных до тех пор, пока он не сдастся.

В этой статье объясняется, почему это происходит, как подтвердить, что вы подверглись атаке с помощью инструментов MySQL, и как реализовать двухуровневую защиту кода, чтобы остановить ее.

Анатомия атаки

Чтобы понять защиту, нужно понять слабость.

По умолчанию WordPress выполняет поиск с использованием MySQL. LIKE запросы с подстановочными знаками на обоих концах (например, LIKE '%term%'). В терминах базы данных ведущий подстановочный знак приводит к тому, что MySQL Полное сканирование таблицы. Он не может эффективно использовать стандартные индексы; ему буквально приходится читать каждую твою строчку wp_posts таблицу с диска, чтобы проверить, существует ли этот термин где-то в содержании.

Эффект мультипликатора

Атака работает путем отправки больших поисковых запросов, содержащих десятки или сотни слов.

ЧИТАТЬ  Trafft: Покажите клиентам свои услуги, расписание и доступность, чтобы записаться на прием | зона Мартех

Если бот ищет 50 случайных слов, WordPress превращает их в один SQL-запрос, содержащий 50 отдельных слов. AND ... LIKE '%word%' статьи. Теперь MySQL приходится выполнять сложные перекрестные ссылки на тысячи строк одновременно для 50 различных терминов.

Несколько десятков таких запросов в секунду могут легко привести к сбою стандартного сервера MySQL.

Диагностика: как узнать, что на вас напали

Если ваш сайт завис, вам нужно посмотреть, что сейчас делает ваша база данных.

Способ 1: ПОКАЗАТЬ СПИСОК ПРОЦЕССОВ (мгновенная диагностика)

Если у вас есть доступ к вашему серверу по SSH или доступ к phpMyAdmin, выполните следующую команду SQL:

SHOW FULL PROCESSLIST;

Посмотрите на результаты. Если вы подверглись поисковой атаке, вы увидите множество процессов в состоянии «Отправка данных» или «Заблокировано», делающих очень длинные запросы. wp_posts который выглядит следующим образом:

SELECT SQL_CALC_FOUND_ROWS wp_posts.ID FROM wp_posts WHERE 1=1 AND (
(wp_posts.post_title LIKE '%word1%') OR (wp_posts.post_content LIKE '%word1%')
) AND (
(wp_posts.post_title LIKE '%word2%') OR (wp_posts.post_content LIKE '%word2%')
) AND ... [repeating for 50+ words] ...
ORDER BY wp_posts.post_date DESC LIMIT 0, 10

Если вы видите, что выполнение этих запросов занимает несколько секунд, вы столкнулись с атакой на исчерпание ресурсов.

Метод 2: Журнал медленных запросов (историческая диагностика)

Если на вашем хостинге включен журнал медленных запросов MySQL, проверьте его. Вы найдете записи, в которых запросы, подобные приведенным выше, занимают необычно много времени (например, Query_time: 5.2345) выполнить.

Решение: двухслойная защита

Мы не можем полагаться на стандартные плагины, чтобы предотвратить это, поскольку атака происходит до загрузки большинства плагинов. Нам нужно перехватить поисковый запрос как можно раньше в процессе выполнения ядра WordPress: pre_get_posts крюк.

Мы реализуем двухуровневую стратегию защиты:

  1. Вышибала (жесткое ограничение на количество символов): Если запрос подозрительно длинный (например, более 200 символов), мы предполагаем, что он вредоносный, и немедленно блокируем его с ошибкой 403 Forbidden. Это защищает PHP и MySQL от любой тяжелой работы.
  2. Фильтр (оптимизация ключевых слов): Для законного поиска по нескольким словам мы удаляем общие «стоп-слова» (например, «the», «a», «is»), а затем сокращаем оставшийся запрос до безопасного количества ключевых слов с высокой ценностью (например, первых 4).
ЧИТАТЬ  Посмотрите эти три фильма, которые появятся на Netflix 1 января | Цифровые тенденции

Выполнение

Добавьте этот код в свою активную тему functions.php файл или, желательно, в плагине для конкретного сайта.

is_main_query() || ! $query->is_search() ) {
        return;
    }

    $search_string = $query->get( 's' );
    if ( empty( $search_string ) || ! is_string( $search_string ) ) {
        return;
    }

    $already_run = true;
    
    // --- CONFIGURATION ---
    $max_characters = 200; 
    $max_keywords   = 4;   
    // ---------------------

    // LAYER 1: Hard Character Limit
    if ( strlen( $search_string ) > $max_characters ) {
        status_header( 403 );
        // Using a plain string instead of a styled template to prevent secondary loop crashes
        die( 'Search query too long. Please refine your search.' ); 
    }

    // LAYER 2: Keyword Optimization
    $stop_words = array(
        // WP Defaults
        'a', 'about', 'an', 'are', 'as', 'at', 'be', 'by', 'com', 'for', 'from', 
        'how', 'in', 'is', 'it', 'of', 'on', 'or', 'that', 'the', 'this', 
        'to', 'was', 'what', 'when', 'where', 'who', 'will', 'with', 'www',
        // Pronouns & Personal Terms
        'i', 'me', 'my', 'myself', 'we', 'our', 'ours', 'ourselves', 'you', 
        'your', 'yours', 'yourself', 'yourselves', 'he', 'him', 'his', 
        'himself', 'she', 'her', 'hers', 'herself', 'its', 'itself', 
        'they', 'them', 'their', 'theirs', 'themselves',
        // Conjunctions & Prepositions
        'and', 'but', 'if', 'or', 'because', 'as', 'until', 'while', 'at', 
        'by', 'for', 'with', 'about', 'into', 'through', 'during', 'before', 
        'after', 'above', 'below', 'to', 'from', 'up', 'down', 'in', 'out', 
        'on', 'off', 'over', 'under'
    );
    
    // Split into words by space, comma, or plus
    $all_words = preg_split( '/[\s,\+]+/', $search_string, -1, PREG_SPLIT_NO_EMPTY );
    
    if ( ! empty( $all_words ) && is_array( $all_words ) ) {
        $meaningful_words = array();
        
        // Use a loop instead of array_filter for maximum PHP compatibility/stability
        foreach ( $all_words as $word ) {
            $clean_word = strtolower( trim( $word ) );
            if ( ! in_array( $clean_word, $stop_words ) ) {
                $meaningful_words[] = $word;
            }
        }

        // If keywords exceed the limit, truncate and update query
        if ( count( $meaningful_words ) > $max_keywords ) {
            $truncated = array_slice( $meaningful_words, 0, $max_keywords );
            $query->set( 's', implode( ' ', $truncated ) );
        }
    }
}

Как это проверить

  1. Тестовый уровень 1: Попробуйте выполнить поиск по большому блоку текста (более 200 символов). Вы должны сразу увидеть стандартную страницу ошибки WordPress с надписью «Поисковой запрос слишком длинный».
  2. Уровень проверки 2: Найдите длинную запоминающуюся фразу вроде: «Я ищу лучшие рецепты итальянской пиццы в центре Чикаго».
  3. Проверьте заголовок страницы результатов поиска. Вы должны видеть, что WordPress на самом деле искал что-то гораздо более короткое, вероятно, просто ключевые слова, такие как: “Рецепты итальянской пиццы в Чикаго”.

Реализуя этот код, вы гарантируете, что какую бы ерунду пользователь или бот ни вставлял в вашу панель поиска, ваша база данных MySQL всегда получит только простой, управляемый запрос.

Source