MAATRIX / Блог / L7-атака или наплыв клиентов: как отличить за пять минут

L7-атака или наплыв клиентов: как отличить за пять минут

MAATRIX

Нагрузка на сервер резко выросла: CPU в потолке, соединений втрое больше обычного, страницы отдаются с задержкой. Первая мысль — либо вас куда-то напечатали и повалил трафик, либо это атака на прикладном уровне, которая маскируется под обычных посетителей. Ошибиться в любую сторону дорого: включить защиту против живой аудитории — потерять заказы в момент, когда сайт наконец заметили, а принять атаку за успех — оставить сервер лежать, пока вы радуетесь графикам. Ниже — пять признаков, по которым это отличается за пять минут по обычным логам nginx, без специального софта.

Почему нельзя решать на глаз

L7 DDoS — это не SYN-флуд и не UDP-мусор, который виден на уровне сети. Атакующий устанавливает полноценное TCP-соединение, проходит TLS-хендшейк и отправляет синтаксически корректный HTTP-запрос — с точки зрения файрвола и балансировщика это неотличимо от обычного браузера. Именно поэтому классическая защита от L3/L4-атак (фильтрация по флагам пакетов, лимиты на полуоткрытые соединения) тут бессильна: сетевой уровень не видит проблемы, она видна только в содержимом запросов и их характере.

Трафик для такой атаки часто идёт не с одного адреса злоумышленника, а с ботнета из заражённых устройств или через пул дешёвых прокси и облачных VPS — то есть у атакующего тоже может быть много разных IP. Поэтому смотреть только на «слишком много запросов с одного адреса» недостаточно: современная L7-атака умеет это обходить. Надёжный вывод даёт не один признак, а совпадение нескольких: если однородность видна и в User-Agent, и в запрашиваемых страницах, и в географии, и во времени — это атака. Если разнородность естественна везде — это люди.

Отдельно стоит исключить внутреннюю причину: иногда сайт «падает» не от внешнего трафика, а от медленного запроса к базе, зациклившегося процесса или утечки памяти, и рост нагрузки путают с атакой. Быстрая проверка: ss -tn state established | wc -l — если соединений действительно много, разбираемся ниже с их природой; если соединений мало, а сервер всё равно захлёбывается — ищите причину внутри, а не снаружи (подробный разбор первых действий при атаке — в статье DDoS-атака: первые действия).

Признак 1: User-Agent и referrer

У живых посетителей набор User-Agent пёстрый: смесь Chrome, Safari, Firefox разных версий, мобильные и десктопные, плюс немного легитимных ботов (Googlebot, Yandex, метрика). Ни одна строка не занимает подавляющее большинство трафика.

awk -F'"' '{print $6}' /var/log/nginx/access.log | sort | uniq -c | sort -rn | head -20

Атака выглядит иначе одним из двух способов. Либо атакующий не маскируется вообще, и в топе — библиотеки вроде python-requests/2.31, Go-http-client/1.1, curl/8.x или вовсе пустая строка. Либо маскируется, но небрежно: один и тот же «свежий Chrome на Windows» повторяется тысячи раз подряд, тогда как у реальной аудитории такого совпадения не бывает — версии ОС и браузера у живых людей естественно разбросаны.

Referrer работает похоже. У органического трафика он разнообразен: часть заходов без referrer (прямой ввод, закладки, мессенджеры вырезают заголовок), часть — с соцсетей, поисковиков, агрегаторов.

awk -F'"' '{print $4}' /var/log/nginx/access.log | sort | uniq -c | sort -rn | head -20

Тревожный сигнал — когда почти весь referrer пуст И User-Agent тоже однороден: живой человек с пустым referrer обычно приходит с разных устройств и версий, а вот скрипт, бьющий по одному URL без referrer и с одним UA, — это уже похоже на прицельный запуск, а не на случайный набор прямых заходов.

Нужен сервер под эту задачу?

Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.

Арендовать сервер

Признак 2: какие страницы запрашивают

Реальный посетитель ходит по сайту: открывает главную, переходит в каталог или статью, подгружает картинки, CSS, JS — набор путей в логах разнообразный, с ожидаемым перекосом в сторону статики.

awk -F'"' '{print $2}' /var/log/nginx/access.log | awk '{print $2}' | sort | uniq -c | sort -rn | head -20

Атака на прикладном уровне обычно метит в одну-две точки — не потому что атакующему лень, а потому что цель другая: не «посмотреть сайт», а максимально нагрузить CPU или базу на каждый запрос. Чаще всего это дорогие по ресурсам эндпоинты: страница поиска, форма логина, эндпоинт с фильтрами каталога, API с тяжёлой выборкой. Полезный частный признак — доля уникальных путей от общего числа запросов:

total=$(wc -l < /var/log/nginx/access.log)
uniq_paths=$(awk -F'"' '{print $2}' /var/log/nginx/access.log | awk '{print $2}' | sort -u | wc -l)
echo "запросов: $total, уникальных путей: $uniq_paths"

Если на десятки тысяч запросов — единицы уникальных путей, это либо очень узкий сценарий использования (например, все грузят один и тот же вирусный пост — тоже нормально), либо атака. Отличить одно от другого помогает второй слой: реальный вирусный трафик на одну страницу всё равно подгружает её статику (картинки, CSS, шрифты) и слегка растекается по соседним ссылкам, а скрипт, добивающий один URL, статику не запрашивает вовсе — он не рендерит страницу, а просто шлёт HTTP-запрос. Ещё одна деталь, которую стоит проверить отдельно, — случайные query-параметры к одному и тому же пути (?x=8f3a1c, ?v=193827): это классический приём обхода кеша, чтобы каждый запрос гарантированно долетал до бэкенда, а не отдавался из кеша nginx.

Признак 3: география и автономные системы

Реальная аудитория обычно соответствует ожидаемой географии бизнеса: если сайт русскоязычный и локальный, основная масса IP — из соответствующих стран и у обычных провайдеров (домашний и мобильный интернет). Для международного сервиса разброс шире, но и тогда прослеживается связь с реальными рынками присутствия.

Быстро посмотреть top-IP и прогнать через geoip/whois:

awk '{print $1}' /var/log/nginx/access.log | sort | uniq -c | sort -rn | head -20
# для каждого подозрительного IP:
whois 203.0.113.10 | grep -i orgname
geoiplookup 203.0.113.10

Признак атаки — не столько «чужая страна» сама по себе (у вас может быть и легитимный зарубежный трафик), сколько происхождение из подсетей дата-центров и облачных провайдеров: whois на топовых IP массово показывает названия вроде хостинг-провайдеров, а не домашних или мобильных операторов. Живые люди почти никогда не сидят на IP облачного VPS-хостинга — а вот дешёвые прокси для атак часто арендуются именно там. Если из топ-20 адресов половина резолвится в хостинг-провайдеров, а не в операторов связи, это весомый аргумент в пользу атаки, особенно в сочетании с однородным UA из предыдущего пункта.

Важная оговорка: этот признак работает как дополнительный, не как единственный. У SaaS с международной аудиторией или у сайта за корпоративным прокси легитимный трафик тоже может идти из дата-центрового диапазона (например, через VPN сотрудников или corporate proxy) — поэтому смотрите на совпадение с остальными признаками, а не делайте вывод по одной географии.

Признак 4: распределение по времени

У органического роста есть форма — растянутая по времени кривая, которая коррелирует с реальным событием: пост опубликован, рассылка ушла, упоминание попало в топ агрегатора. Трафик нарастает за минуты-часы, достигает пика и постепенно спадает, повторяя типичный суточный ритм вашей аудитории (для B2C-аудитории — спад глубокой ночью по местному времени пользователей).

awk -F'[' '{print $2}' /var/log/nginx/access.log | awk -F: '{print $2":"$3}' | uniq -c

Эта команда покажет число запросов по каждой минуте лога. У живого трафика график плавный: разгон, пик, спад, без резких ступенек. У атаки чаще виден один из двух паттернов: почти вертикальный скачок нагрузки за считаные секунды (скрипт запустили — и всё) либо, наоборот, подозрительно ровный поток без обычных для людей колебаний — механически равномерная частота запросов, которую человеческое поведение почти никогда не воспроизводит. Ещё один сигнал — трафик не спадает ночью по часовому поясу вашей типичной аудитории, хотя раньше всегда спадал: боты не спят.

Учитывайте, что это ориентировочный, а не абсолютный критерий — рекламная кампания с точным временем старта тоже может дать резкий скачок. Здесь снова помогает пересечение с другими признаками: резкий скачок трафика с разнообразными UA, referrer с рекламной площадки и живой географией — это успешный запуск кампании; тот же резкий скачок с однородным UA и пустыми referrer — это атака.

Пятиминутный чек-лист: команды для быстрой проверки

Свести всё в один скрипт, который за один проход по логу выдаёт сводку по всем четырём признакам:

#!/bin/bash
LOG=${1:-/var/log/nginx/access.log}
N=${2:-5000}  # последние N строк

TAIL=$(tail -n "$N" "$LOG")

echo "=== Топ User-Agent ==="
echo "$TAIL" | awk -F'"' '{print $6}' | sort | uniq -c | sort -rn | head -5

echo "=== Топ Referrer ==="
echo "$TAIL" | awk -F'"' '{print $4}' | sort | uniq -c | sort -rn | head -5

echo "=== Топ пути ==="
echo "$TAIL" | awk -F'"' '{print $2}' | awk '{print $2}' | sort | uniq -c | sort -rn | head -10

echo "=== Уникальность путей и IP ==="
echo "запросов: $N"
echo "уникальных путей: $(echo "$TAIL" | awk -F'"' '{print $2}' | awk '{print $2}' | sort -u | wc -l)"
echo "уникальных IP: $(echo "$TAIL" | awk '{print $1}' | sort -u | wc -l)"

echo "=== Топ IP ==="
echo "$TAIL" | awk '{print $1}' | sort | uniq -c | sort -rn | head -10

echo "=== Запросов в минуту ==="
echo "$TAIL" | awk -F'[' '{print $2}' | awk -F: '{print $2":"$3}' | uniq -c

Сохраните как check-traffic.sh, дайте права chmod +x check-traffic.sh и запустите ./check-traffic.sh. Полминуты на прогон и ещё пару минут на чтение вывода — этого хватает, чтобы отсеять очевидные случаи. Сводная таблица для быстрой сверки:

ПризнакПохоже на людейПохоже на L7-атаку
User-Agentдесятки разных версий браузеров1-2 строки на большинство запросов, либо библиотеки/пусто
Referrerсмесь пустых, соцсетей, поисковиковпочти весь пустой или один и тот же
Путимного уникальных, есть статика (css/js/img)1-2 «дорогих» пути, статика не запрашивается
Query-параметрыестественные (?page=2, ?id=42)случайные (?x=8f3a1c) для обхода кеша
География/ASNсоответствует аудитории, операторы связиподсети хостинг-провайдеров и облаков
Времяплавная кривая, суточный ритмрезкая ступенька или неестественно ровный поток

Что делать по результатам

Если признаки указывают на атаку, не начинайте с блокировки по IP — при распределённой атаке это бесконечная игра в вихрь. Сначала ограничьте нагрузку на конкретный уязвимый эндпоинт: rate limiting на уровне nginx режет проблему в её источнике, не трогая остальной трафик. Если атака бьёт по одному URL и в одном UA-паттерне — правило limit_req именно на этот location часто снимает 90% проблемы за минуты. Для системной защиты на постоянной основе (не только на этот случай) стоит посмотреть в сторону CDN/WAF-прокси перед сервером и общих мер, описанных в статье про защиту от DDoS на выделенном сервере.

Если же признаки говорят о легитимном наплыве — не мешайте ему выжить. Первым делом усильте кеширование отдающихся страниц (даже TTL в 30-60 секунд на динамической странице радикально снижает нагрузку на бэкенд при одинаковых запросах), временно отключите тяжёлую персонализацию, если она есть, и проверьте, не упирается ли сервер в конкретный ресурс — CPU, память, диск или число соединений к базе (это разбирается в статье как узнать, кто нагружает сервер). Если ресурсов объективно не хватает, честнее временно расширить конфигурацию, чем героически латать дыры под нагрузкой.

Держите в уме, что диагностика не разовая: атакующие подстраиваются, если видят, что первая волна отбита, — конфигурация запросов может измениться через 10-15 минут. Прогоните чек-лист повторно после принятых мер, чтобы убедиться, что картина не превратилась в новый паттерн атаки.

Нужен сервер под эту задачу?

Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.

Арендовать сервер

Нужны сами нейросети для контента?

Генерируйте изображения, видео и озвучку нейросетями на falapi.io — десятки моделей в одном окне. Оплата картой РФ и по СБП.

Частые вопросы

Признаки смешанные — часть похожа на атаку, часть на обычных людей. Что делать?

Такое бывает при двух сценариях: настоящий наплыв, к которому по-быстрому пристроился оппортунистический скан или мелкая атака, либо легитимный трафик идёт через CDN/мобильных операторов с NAT, из-за чего много пользователей выглядят как несколько IP. В этом случае не применяйте меры ко всему трафику сразу — выделите именно однородный по UA/пути/времени сегмент и ограничивайте только его, например через limit_req на конкретный location, а не блокировкой по широкой подсети.

Может ли продвинутая L7-атака полностью имитировать реальных пользователей — с ротацией UA и headless-браузером?

Технически да, и тогда перечисленные признаки размываются. В этом случае помогает поведенческий срез: настоящий браузер после HTML почти всегда подгружает CSS, JS и картинки этой же страницы, ставит cookie и делает второй запрос; скрипт, даже с честным UA, чаще всего запрашивает только целевой URL и не возвращается. Соотношение запросов к статике и к HTML — более устойчивый индикатор, чем сам UA.

Нужен ли для этой диагностики платный WAF или CDN?

Нет, всё описанное делается по обычному access-логу nginx стандартными утилитами (awk, sort, uniq, whois). WAF и CDN полезны как следующий шаг — для защиты после того, как вы поняли, что это атака, — но не для самой диагностики.

Логи не пишутся или отключены для скорости — как быть без них?

Временно включите буферизованный access_log (access_log /var/log/nginx/access.log combined buffer=64k flush=5s; — буферизация почти не сказывается на производительности) хотя бы на несколько минут, этого достаточно для снятия картины. Если совсем нет времени ждать — смотрите текущие соединения через ss -tn state established и группируйте по адресам вручную, это грубее, но быстрее нуля.

Обсудить статью, задать вопрос или начать новую тему

Есть вопрос по этой статье, идея для обсуждения или просто хотите поделиться опытом? Сообщество MAATRIX ждёт. Для общения, пожалуйста, зарегистрируйтесь в нашем личном кабинете.

Перейти в сообщество →