Все, что у нас было это один сервер(Intel(R) Core(TM) i7-4790K/32 Gb RAM(nginx+php-fpm+MariaDB), клиент, который не хочет уходить под защиту CloudFlare и 7 Layer DDoS(http) от 2.3k до 3.5k rps(ну то есть где-то примерно 259200000 запросов к серверу в сутки).

С этим клиентом я давно привык к мелким DDoS’ам, то канал зафлудят выдав на несколько минут под гигабит в секунду udp-флуда, то начинают с ограниченного количества IPшников долбится по / веб-сервера, то пытаются выжрать память у игрового сервера.

Если с первым, канальным флудом, что-то поделать может только хостер(хвала online.net которые таки флуд в гигабит переваривают и достаточно быстро на автомате включают защиту, начинают отсекать это), то прочее на мне.

Пока были атаки с ограниченного количества адресов все было достаточно просто, nginx’у говорим

limit_req_zone $binary_remote_addr zone=one:10m rate=NNr/s;

в nginx.conf, limit_req zone=one burst=NN+MM; в конфиге по нужному домену и fail2ban c nginx-limit-req провожающий наших гостей на хутор бабочек ловить. Подолбились, уперлись в лимит от nginx’а, словили бан от fail2ban и больше нам не мешают.

А вот когда таки пришли в гости с какого-то толстого ботнета и эти тысячи реквестов в секунду пошли с тысяч разных адресов наши фокусы срабатывать перестали. nginx еще как-то выживал, а вот сидящий за ним php-fpm говорил, что он — грустный панда и не хотел общаться с миром. В ограничения nginx’а они больше не упирались(видать за несколько месяцев поняли, что большое количество запросов с одного адреса приводит к его бану и ты уже ничего сделать не сможешь). Эргил почесал репу и понял, что нужно что-то делать.

Первым делом, первым делом самолеты… А! Нет. Первым делом, зная, что у нашего клиента нет посетителей в Китае, Гонконге и прочих Вьетнамах мы берем в руки шашки, в смысле ipset, берем данные по сетям по странам с ipdeny.com и отправляем смело все эти страны гулять. Ничего сам для этого не рожал, нашел готовый скрипт берущий на вход указания сетями каких стран ему оперировать, запустил и проводил Китай, Вьетнам, Сингапур, Гонконг.

Нам полегчало где-то минут на 30, но противник, судя по всему, заметил, что мы полностью пришли в себя и обиделся. Полез смотреть в логи, что же у нас с UA атакующих. Обнаружил, что UserAgent’ы пытаются выглядеть валидно, но при этом относятся к устаревшим или несуществующим версиям браузеров. Нашел на github’е прекрасного человека, который уже подготовил списки с кучей бэдботов в UA(https://github.com/mitchellkrogza/) взял его конфиги. Снова полегчало, но снова ненадолго. Почесал еще в репе, подумал и решил, что учитывая самообновление браузеров я могу пойти дальше и просто отсечь все UserAgent’ы для старых версий браузеров, что и было проделано В nginx.conf

map $http_user_agent $outdated {
default 0;
"~MSIE [1-9]\." 1;
"~Mozilla.*Firefox/[1-9]\." 1;
"~Mozilla.*Firefox/[0-4][0-9]\." 1;
"~Opera.*Version/[0-9]\." 1;
"~Opera.*Version/[0-2][0-9]\." 1;
"~Opera.*Version/3[0-5]\." 1;
"~AppleWebKit.*Version/[0-6]\..*Safari" 1;
"~Chrome/[0-9]\." 1;
"~Chrome/[0-4][0-9]\." 1;
}

Определяем какие версии браузеров мы будем считать устаревшими. В конфиг нашего домена

if ($outdated = 1){
return 444;
}

Если к нам пришли со старой версией браузера, то nginx просто сбрасывает коннект. И

if ($http_user_agent = "") {
return 444;
}

Если к нам пришли вообще без UserAgent’а, то тоже сбрасываем коннект. Перезапускаем nginx и смотрим, как ботнет по прежнему пытается долбиться, получает сброс коннекта и уходит курить бамбук.

За последующие два дня наблюдаем, как к серверу приходит еще около 500 миллионов запросов от ботнета и как они все дружно покуривают бамбук в коридоре, а сервер продолжает работать, словно ничего не происходит. Уж не знаю кому отдавил в этот раз хвост сей славный мальчик, но таки DDoS был интересный с точки зрения зрения защиты от него, при том, что клиент не хочет уходить под защиту CDN CloudFlare.

По результату могу сказать, что Layer 7 DDoS проще в отбитии своими силами, ибо тут все в моей власти, а при забитии канала нихера не в моей власти и что я таки могу отмахаться от 3k rps своими силами.

К сожалению не для всех клиентов можно включить такое ограничение по UA, ибо у некоторых приходят со старых версий браузеров, но, по факту, ботнет пытался прикидываться совсем старыми версиями, для того же Хрома версия фальшивого UA не превышала 30, то есть я даже чуть превысил в настройках нужные версии, но лучше перебдеть, чем недобдеть.