Pull to refresh
97.11
Nixys
DevOps, DevSecOps, MLOps — IT Solutions Integrator

Как защититься от dos/ddos, или Как я начал вновь высыпаться по ночам

Reading time 16 min
Views 24K

Предисловие

Приветствую тебя, дорогой читатель. Скорее всего, если ты это читаешь, то уже очень устал получать кучу алертов о том, что твоя площадка загибается от регулярных набегов печенегов ботов или других нежелательных посетителей контента. Я надеюсь, что эта статья поможет тебе спать спокойно и оградит тебя от недугов, а также внесет больше ясности в твое понимание теории и практики защиты от dos и ddos. Приятного чтения!


Глава 1: “Знай своего врага.” - Сунь Цзы

Что такое Dos и Ddos, и в чём их отличия?

Dos, или по-другому Denial of Service - «отказ в обслуживании». Это атака со стороны одиночного IP-адреса, связанная с отправкой нелегитимного трафика и приводящая к неработоспособности системы, что, в свою очередь, приводит к простою площадки или сервиса и потере финансовой составляющей.

Ddos, или Distributed Denial of Service - «распределенный отказ в обслуживании».  Отличие данной атаки от описанной выше в том, что отправка трафика в данном случае будет идти с различных IP-адресов. Этот аспект приводит к сложности защиты сервисов.

Как распознать возникновение атаки на инфраструктуру?

В случае, если на вашей машине, локальной или виртуальной, резко повысилась нагрузка на CPU и увеличилось потребление RAM, то, вероятнее всего, вы стали жертвой криво залитого кода или же ddos/dos-атаки. Распознать подобное поведение и определиться с окончательным выбором варианта ответа нам помогут следующие шаги.

Во-первых, как уже было написано выше, - если у вас установлен мониторинг, и вы видите резкие скачки на графиках ресурсопотребления, к примеру:

Также вы заметите увеличение количества коннектов на вашем сервисе обработчике данных. Для примера мы рассматриваем стандартный LEMP-стек Nginx + Apache + Mysql,  а значит в момент проблемы мы фиксируем резкий скачок соединений:

Во-вторых можно произвести анализ запросов за время возникновения проблемы. В этом, как правило, могут помочь однострочные скрипты, которые полезно иметь каждому системному администратору под рукой, данные скрипты вы можете написать самостоятельно, изучив команды чуть подробнее или воспользоваться нашим готовым решением. Ниже команда для парсинга логов за последние 10000 и вывод в top IP адресов, встречающихся наиболее часто:

tail -10000 access.log | awk '{print $1}'| sort -nr | uniq -c | sort -nr | head

Так можно узнать количество уникальных IP, после чего можно сравнить с результатами за предыдущие сутки и узнать было ли значительное увеличение трафика:

cat access.log | awk '{print $1}'| sort -nr | uniq -c | wc -l

Следом представляем отличную команду для парсинга IP-адресов в момент фиксирования проблемы, а именно по дате и временному промежутку:

head access.log | grep 26/Apr/2021:1[1-2]: | awk '{print $1}'| sort -nr | uniq -c | sort -nr

Теперь давайте посмотрим примеры на практике нелегитимного трафика:

head -20 access.log | grep "25/Jul/2022:00:" | awk '{print $1}' | sort | uniq -c | sort -nr
   4150 45.155.53.76
   3550 84.38.189.56
   3184 5.45.207.189
   233 5.255.253.188
   233 45.10.217.121
   233 92.119.203.156
   229 5.45.207.112
   223 84.38.189.54
   200 109.194.11.25
   147 5.255.253.160

В этом примере первое, что бросается в глаза - это около 4000 запросов за последний час с 00:00. Из этого можно сделать вывод, что это явно не обычный пользователь, которому нравится заходить на сайт. Также одним из отличительных признаков ddos-атаки можно назвать регулярное изменение user agent в каждом запросе, что наводит на мысль о машинном создании запроса.

Что же такое user agent?

User agent — идентификационная строка клиентского приложения; обычно используется для приложений, осуществляющих доступ к веб-сайтам — браузеров, поисковых роботов и «пауков», мобильных телефонов и других устройств со встроенным доступом к веб-ресурсам.

Например:

tail -10 access.log | grep 185.250.45.31
185.250.45.31 [Via:NGENIX; X-Proxy-Name:-] (RU) "www.testsite.ru" [24/Jul/2021:21:27:24 +0300]    200     "GET /ajax/rq_list.php?product_id=10692404 HTTP/1.1"    0.049 (0.048)   Upstream:10.250.0.5:443 1963    "https://www.testsite.ru/ajax/rq_list.php?product_id=10692404" "Mozilla/5.5 (Windows; I; Windows NT 6.1; en-us) Chrome/36.6.59.965"    "blocked=0"     "whitelistCOUNTRY=1"    "whitelistIP=0" "whitelistORG=0" 
185.250.45.31 [Via:NGENIX; X-Proxy-Name:-] (RU) "www.testsite.ru" [24/Jul/2021:21:27:24 +0300]    200     "GET /ajax/rq_list.php?product_id=10692404 HTTP/1.1"    0.056 (0.056)   Upstream:10.250.0.5:443 1963    "https://www.testsite.ru/ajax/rq_list.php?product_id=10692404" "Mozilla/5.3 (compatible; Windows NT 6.6; WOW64; en-us) Chrome/35.1.309.843 Safari/551.56"      "blocked=0"     "whitelistCOUNTRY=1"    "whitelistIP=0" "whitelistORG=0" 
185.250.45.31 [Via:NGENIX; X-Proxy-Name:-] (RU) "www.testsite.ru" [24/Jul/2021:21:27:27 +0300]    200     "GET /ajax/rq_list.php?product_id=10692404 HTTP/1.1"    0.063 (0.064)   Upstream:10.250.0.5:443 1963    "https://www.testsite.ru/ajax/rq_list.php?product_id=10692404" "Mozilla/5.9 (Linux (Wine); Windows NT 7.2; ru-ru) like Gecko Chrome/34.8.208.96 Safari/639.27" "blocked=0"     "whitelistCOUNTRY=1"    "whitelistIP=0" "whitelistORG=0" 
185.250.45.31 [Via:NGENIX; X-Proxy-Name:-] (RU) "www.testsite.ru" [24/Jul/2021:21:27:27 +0300]    200     "GET /ajax/rq_list.php?product_id=10692404 HTTP/1.1"    0.071 (0.072)   Upstream:10.250.0.5:443 1963    "https://www.testsite.ru/ajax/rq_list.php?product_id=10692404" "Mozilla/5.0 (compatible; U; Windows NT 6.3; en-us) Chrome/35.1.226.692"        "blocked=0"     "whitelistCOUNTRY=1"    "whitelistIP=0" "whitelistORG=0" 
185.250.45.31 [Via:NGENIX; X-Proxy-Name:-] (RU) "www.testsite.ru" [24/Jul/2021:21:27:28 +0300]    200     "GET /ajax/rq_list.php?product_id=10692404 HTTP/1.1"    0.073 (0.072)   Upstream:10.250.0.5:443 1963    "https://www.testsite.ru/ajax/rq_list.php?product_id=10692404" "Mozilla/5.0 (Windows; Windows NT 6.9; x64; en-us) KHTML/4.3.5 (like Gecko) Chrome/39.3.54.483" "blocked=0"     "whitelistCOUNTRY=1"    "whitelistIP=0" "whitelistORG=0" 

Здесь прекрасно видно, как на протяжении 1 минуты useragent потенциального пользователя в каждом запросе меняет браузер на Chrome, Mozilla, Safari. Как и саму ОС, с которой происходит отправка Windows, Linux.

Итак, когда мы чуть-чуть познакомились с теорией, настало время практики. В частности, мы поднимем стандартный Nginx на OC Debian 10 в качестве обработчика статического контента и Apache в качестве backend и произведем стресс тест нашей площадки.

Глава 2: “Лучшая защита - нападение” - Александр Македонский.

Начнём… Давайте поставим актуальный Nginx из официальных репозиториев для дальнейшей работы.

1.1. Ставим необходимые библиотеки:

apt install curl gnupg2 ca-certificates lsb-release debian-archive-keyring

1.2. Импортируем официальный ключ подписи:

curl https://nginx.org/keys/nginx_signing.key | gpg --dearmor \
    | tee /usr/share/keyrings/nginx-archive-keyring.gpg >/dev/null

1.3. Проверяем его правильность:

gpg --dry-run --quiet --import --import-options import-show /usr/share/keyrings/nginx-archive-keyring.gpg

1.4. Добавляем репозитории:

echo "deb [signed-by=/usr/share/keyrings/nginx-archive-keyring.gpg] \
http://nginx.org/packages/debian `lsb_release -cs` nginx" \
    | tee /etc/apt/sources.list.d/nginx.list

1.5. Настраиваем приоритет наших пакетов, над пакетами из основного дистрибутива:

echo -e "Package: *\nPin: origin nginx.org\nPin: release o=nginx\nPin-Priority: 900\n" \
    | tee /etc/apt/preferences.d/99nginx

1.6. Перечитываем репозитории и ставим наш Nginx

apt update
apt install -y nginx

2. Проверяем, что Nginx установлен корректно и уже автоматически запустился.

systemctl status nginx
● nginx.service - A high performance web server and a reverse proxy server
  Loaded: loaded (/lib/systemd/system/nginx.service; enabled; vendor preset: enabled)
  Active: active (running) since Mon 2022-01-31 18:19:12 +07; 7s ago
    Docs: man:nginx(8)
Main PID: 9381 (nginx)
   Tasks: 5 (limit: 4915)
  Memory: 5.8M
  CGroup: /system.slice/nginx.service
          ├─9381 nginx: master process /usr/sbin/nginx -g daemon on; master_process on;
          ├─9382 nginx: worker process
          ├─9383 nginx: worker process
          ├─9384 nginx: worker process
          └─9385 nginx: worker process

янв 31 18:19:12 user systemd[1]: Starting A high performance web server and a reverse proxy server...
янв 31 18:19:12 user systemd[1]: Started A high performance web server and a reverse proxy server.

3. Теперь напишем простую конфигурацию для виртуального хоста и проведём тестирование.

nano /etc/nginx/conf.d/default

Конфигурация:

server {
       listen 80 ;

       root /var/www/html;

       server_name www.zashitimsa_ot_ddos.ru;

       location / {
               try_files $uri $uri/ =404;
       }

}

4. Прописываем необходимую запись к себе в hosts, чтобы иметь возможность открыть наш созданный сайт.

nano /etc/hosts

Конфигурация:

$наш_ip_адрес www.zashitimsa_ot_ddos.ru

5. Делаем проверку и получаем подобный результат.

p.s. Картинка

Картинка была заготовлена изначально и положена в файлы площадки.

6. Теперь проверим, как наш Nginx выдержит стресс-тест. Используем для этого любую тестовую утилиту для Dos. Я в качестве примера использую GoldenEye. Ссылка на источник прилагается.

Её запуск можно произвести как со своей локальной машины, так и с другой  виртуальной машины для наглядности.

Перемещаемся в рабочий каталог:

cd /opt

И клонируем себе репозиторий:

git clone https://github.com/jseidl/GoldenEye.git
cd ./GoldenEye

Если у вас изначально нету git и python, то их можно также легко установить себе на машину следующими командами:

apt install git python3.9

Теперь делаем тестовый запуск и смотрим на логи и результат:

python3 goldeneye.py http://www.zashitimsa_ot_ddos.ru/test.png -w 50 -s 1500 -m random -d
GoldenEye v2.1 by Jan Seidl <jseidl@wroot.org>

Hitting webserver in mode 'get' with 2500 workers running 500 connections each. Hit CTRL+C to cancel.

Starting 50 concurrent workers

7. Результат.

Площадка не отдает контент:

В логах видим, что на площадку было отправлено 3000 беспорядочных запросов Nginx.

head /var/log/nginx/access.log | grep 07/Feb/2022:05: | awk '{print $1}'| sort -nr | uniq -c | sort -nr
   3002 62.109.28.95

При этом все запросы имеют примерно следующее содержание:

tail -3 access.log 
62.109.28.95 - - [07/Feb/2022:05:50:40 +0000] "GET /test.png?C5fpRAtsX=mDtamkj&fvHhGpqK5E=wFsRJifnxpAr8yXYA8Ip HTTP/1.1" 200 119941 "http://www.zashitimsa_ot_ddos.ru/mCiN2DNf7Y?N1tw=c7aqmB&0lFIpn=pUYexNiiySDc2&fw1h=3KiPFpk30NerKd6&2F1bOYVUhl=JoFsDn2&fg7ljW=b7KNWm&qE2=QtSctM2c53dVRUlx&eaQ=aTP18q14oKF" "Mozilla/5.0 (compatible; MSIE 7.0b; Windows NT.6.2; .NET CLR 2.5.24981; WOW64)"
62.109.28.95 - - [07/Feb/2022:05:50:40 +0000] "GET /test.png?lTbPcEcrHp=24ohNGEqR0 HTTP/1.1" 200 138765 "-" "Mozilla/5.0 (compatible; MSIE 7.0; Macintosh; .NET CLR 3.0.6224; Intel Mac OS X 10_2_5)"
62.109.28.95 - - [07/Feb/2022:05:50:40 +0000] "GET /test.png?jUqMn0gKkI=w2EUD4Ycvt&dSYvge=x0W&vXBaoy7=pvpl21LV&1tssU73vTd=eoqNCWqcv60&BG1FRwnEV2=8qnklbsrP HTTP/1.1" 200 121389 "-" "Mozilla/5.0 (Windows NT 5.1; WOW64) AppleWebKit/537.35 (KHTML, like Gecko) Chrome/27.0.229.36 Safari/536.2"

Это привело к исчерпанию свободных workers обработчиков сервиса:

tail -5 /var/log/nginx/error.log
2022/02/07 05:50:30 [alert] 29231#29231: 768 worker_connections are not enough
2022/02/07 05:50:30 [alert] 29231#29231: 768 worker_connections are not enough
2022/02/07 05:50:30 [alert] 29231#29231: 768 worker_connections are not enough
2022/02/07 05:50:30 [alert] 29231#29231: 768 worker_connections are not enough
2022/02/07 05:50:30 [alert] 29231#29231: 768 worker_connections are not enough
p.s. Предосторожность!

Будьте аккуратны с GoldenEye, так как во время тестирования он потребляет основные ресурсы сервера и, как правило, при неправильном выставлении параметров из серии:

python3 goldeneye.py http://www.zashitimsa_ot_ddos.ru/test.png -w 5000000 -s 15000000 -m random -d

Может привести к исчерпанию свободных ресурсов сервера и к его зависанию.

Глава 3: “В сражении само по себе численное превосходство не дает преимущества. Не надо идти в атаку, опираясь только на голую военную мощь.” - Сунь Цзы

После того, как наша площадка спустя непродолжительное время упала под натиском атаки, можно пробовать выстраивать защиту, которая сможет помочь избежать нелегитимного трафика и дать возможность почувствовать себя крутым IT-шником.

Перед этим необходимо ответить себе на следующие вопросы:

  1. От каких атак я хочу защититься?

  2. Хочу ли я отсеять запросы ботов?

  3. Как не потерять трафик от реальных пользователей?

Приступим...
Разумеется, для тех, кто уже имел опыт работы с Nginx, не будет сюрпризом функция ‘rate’. Для тех, кто не имел такого опыта, ниже мы подробнее рассмотрим эту функцию: что это и с чем это едят.

Шаг первый ‘rate’:

rate - настраиваемая функция, которая позволяет вам ограничить количество HTTP-запросов, которые пользователь может сделать за определенный период времени.

1. Производим добавление зоны в блок server нашего виртуального хоста в корневой location:

Конфигурация:

limit_req_zone $binary_remote_addr zone=shield:10m rate=1r/s;

server {
       listen 80 ;

       root /var/www/html;

       server_name www.zashitimsa_ot_ddos.ru;

       location / {
              limit_req zone=shield;
               try_files $uri $uri/ =404;
       }

}

Чтобы понимать, что мы пишем, разберём сразу несколько ‘лемм’ данной настройки:

zone   /// Ни для кого не будет секретом, что зона представляет из себя зону общей памяти, используемую для хранение IP адресов
zone=shield  /// Название зоны, оно может быть любым
$binary_remote_addr  /// переменная содержащая в себе двоичный IP адрес
10m  /// размер зоны памяти в мегабайтах                                                                                
rate=1r/s /// количество requests в секунду, в данном случае 1 запрос в секунду

Результаты:

После произведения небольшого теста мы сразу увидим в логах следующую картину работы нашей настройки:

head access.log
62.109.28.95 - - [07/Feb/2022:06:08:08 +0000] "GET /test.png?gtv0SN=QwAgT&6SAGxK3h=AFw0opHJed3XpCtwHb HTTP/1.1" 200 189721 "-" "Mozilla/5.0 (Windows NT 5.1; WOW64) AppleWebKit/535.20 (KHTML, like Gecko) Version/5.0.4 Safari/536.21"
62.109.28.95 - - [07/Feb/2022:06:08:08 +0000] "GET /test.png?c6aJYc=lwveJ5aI76xw&ogFuK8R4W=CUqFlTXSrhT1S&F3v=R7EhYI7gpucmbq4&xqN=cq3coSVvPT6&HHq=vjnt7FFyKLx HTTP/1.1" 503 213 "-" "Mozilla/5.0 (Windows NT 6.3; WOW64) Gecko/20042612 Firefox/19.0"
62.109.28.95 - - [07/Feb/2022:06:08:08 +0000] "GET /test.png?2L6Ymgh=mvoXScoSmiaM&mjjkt3o=Lkwyw&5I1ym=7VKefXOma HTTP/1.1" 503 615 "http://www.google.com/xNlsQ3?1nvky0BRyy=JmTICugXrcPMXx0DC" "Mozilla/5.0 (compatible; MSIE 9.0; Macintosh; .NET CLR 2.2.26969; Intel Mac OS X 11_1_1)"
62.109.28.95 - - [07/Feb/2022:06:08:08 +0000] "GET /test.png?Xk4y=xsyeB7FObY3J&TQoJ5=VLTnHP HTTP/1.1" 503 615 "http://www.zashitimsa_ot_ddos.ru/TRvKqc" "Mozilla/5.0 (Windows; U; MSIE 7.0; Macintosh; .NET CLR 3.5.13570; Intel Mac OS X 11_0_5)"
62.109.28.95 - - [07/Feb/2022:06:08:08 +0000] "GET /test.png?A0wPrP=xcKcOdMTSFEGqaUw1&C4lwH=YcQgUkhR1QOI&NCeuc2=LDW5odrQN2bNcWhn2 HTTP/1.1" 503 213 "http://www.zashitimsa_ot_ddos.ru/IdMNN4?CKf7Ux=Jv1CuJ&kah4l8EofJ=o0BPFDqnOE5XWR&iJvEuVR=LEUud0hfi2m&0fRWX0=Fx6SkHP5VRIuJKt&xNQKBnLm=GqquF1C7PEWiKiHD8jG&thesU=HG80V0N&bWtoxEG=CpK8ju5E6lmYm7rOwsyC&wPt=uVQSsyk7XrW7Eq1h" "Mozilla/5.0 (Macintosh; Intel Mac OS X 11_1_0) Gecko/20103004 Firefox/15.0"
62.109.28.95 - - [07/Feb/2022:06:08:08 +0000] "GET /test.png?5O0=3DmuAKsJUVPpdU&TkKL=wJJpKSqOo HTTP/1.1" 503 615 "http://www.yandex.com/ehfnY5" "Mozilla/5.0 (Windows NT.6.2; WOW64) AppleWebKit/537.19 (KHTML, like Gecko) Chrome/17.0.1671.100 Safari/536.22"
62.109.28.95 - - [07/Feb/2022:06:08:08 +0000] "GET /test.png?5ra=7qBQLV&h3YaO=JNUwUUpq HTTP/1.1" 503 213 "-" "Mozilla/5.0 (Windows NT 5.1; Win64; x64) Gecko/20072512 Firefox/11.0"
62.109.28.95 - - [07/Feb/2022:06:08:08 +0000] "GET /test.png?NiU=O3lRfkyh4cDRKo&KWEgQScD0=A4uYEw5rCUI55yt1&C5qjWevh=BJp&qY7q77=XlkE0 HTTP/1.1" 503 615 "http://www.google.com/gwqPjY?SnC=QjCvRl6WkihbOXx3VD&YBbXQ=kfK&u8y6r=qBMhgA67RbfqNOG&CH1jrHn=nJEpNgIdhXq6eP6AL6Y&6u2CM=mjry&KMge75d=4VjNynX&PVU=vWLeLCMRQ1O&ayQVLV=ynE0qdxKmwyQUR6X&uTwvDJU=gB86jE1bJh6PTp&31xQy=NYqINsYwjx8gx8" "Mozilla/5.0 (Windows; U; MSIE 6.0; Windows NT 6.1; Trident/4.0; WOW64)"
62.109.28.95 - - [07/Feb/2022:06:08:08 +0000] "GET /test.png?wCoex=PrlSPlMIAkWGd3J&e7xBA6=ltFAGNQlQHCeGyh24&EWMvYuRt5=57lPG26Mq HTTP/1.1" 503 213 "http://www.yandex.com/loiWFn8?EcOgc=N44Hh1NgNpsTAF&H3dkdP5sps=MW6wACSn&YU4xDEL22u=3QnCuKkybO&MvpI4=RSHViVAvsScoE&d7bQuVeMms=FcGUbmWv&bR4P63j=TolMsDcX0GmrXHUQB&E8A8jR2wf=jl2BA4ipBva&xKgBJB=xnqJAic1ePkX81UfI" "Mozilla/5.0 (Linux i386; X11) Gecko/20100505 Firefox/25.0"
62.109.28.95 - - [07/Feb/2022:06:08:08 +0000] "GET /test.png?GBSOIJ=IVlXF&F7EoI30=bcRHF6ej2vX4i2vj&TE7=mWfJ2E47oe37cgjegjL&x4QKBtRDW=USvUq HTTP/1.1" 503 213 "http://www.baidu.com/GLbGL6q" "Mozilla/5.0 (Linux x86_64; X11) Gecko/20072512 Firefox/11.0"

Отсюда мы видим, 1 запрос получил 200-й код ответа, после чего все остальные запросы получали 503-й код, говорящий о том, что сервер не готов обработать данный запрос. Прекрасно - мы на верном пути.

После того как мы настроили данную защиту, мы защитились от вредоносных IP-адресов, которые создают ненужные запросы, но что, если мы представим ситуацию, когда к нам заглянут толпы поисковых ботов не принадлежащие Yandex, Google, Mail, исходя из нашей настройки 1 запрос будет всегда обрабатываться корректно, но нужен ли он нам?

Шаг второй ‘блокировка по user_agent’

Производим настройку блокировки по user_agent, добавим в наш блок сервера интересное условие для блокировки наиболее популярных поисковых ботов и получим финальную конфигурацию:

limit_req_zone $binary_remote_addr zone=shield:10m rate=1r/s

server {
       listen 80 ;

       root /var/www/html;

       server_name www.zashitimsa_ot_ddos.ru;

       
      if ( $http_user_agent ~* (bingbot|AhrefsBot|Ruby|PetalBot|SemrushBot|MJ12bot) ){
               return 403;
       }

       location / {
              limit_req zone=shield;
               try_files $uri $uri/ =404;
       }

}

Результаты:

Теперь боты, обращающиеся с данным user agent автоматически получают 403 независимо от запроса и отправляются отдыхать, не затрагивая нашу площадку.

62.109.28.95 - - [07/Feb/2022:06:27:41 +0000] "GET /test.png?OBDmsO6=foc&kbCf=xy6VgK4QYN HTTP/1.1" 403 571 "-" "Mozilla/5.0 (MJ12bot; Intel Mac OS X 10_0_1) AppleWebKit/537.18 (KHTML, like Gecko) Chrome/30.0.1475.18 Safari/535.5"
62.109.28.95 - - [07/Feb/2022:06:27:41 +0000] "GET /test.png?TteMB=tmrbqmDJabtTAT&cGr4=p2Yxpkdku&Afk20eI=wTibBYkQRqCwOxgh1HD&cULj3rci=POV2pj&rWtHK0=UwnWlr3el HTTP/1.1" 403 571 "-" "Mozilla/5.0 (Windows; U; MSIE 7.0; MJ12bot; .NET CLR 2.0.4936; Intel Mac OS X 11_1_1)"
62.109.28.95 - - [07/Feb/2022:06:27:41 +0000] "GET /test.png?iAHhFb6HF=W8YtpeInTbX774IOHWM&VFU2BXL=Kgfe0n5d631 HTTP/1.1" 403 140 "-" "Mozilla/5.0 (MJ12bot; Intel Mac OS X 11_1_1) Gecko/20053010 Firefox/16.0"
62.109.28.95 - - [07/Feb/2022:06:27:41 +0000] "GET /test.png?SH41W=bSxf8dkWfwK&W7yR=lqY0s0 HTTP/1.1" 403 169 "-" "Mozilla/5.0 (MJ12bot; Intel Mac OS X 11_3_3) Gecko/20091604 Firefox/10.0"
62.109.28.95 - - [07/Feb/2022:06:27:41 +0000] "GET /test.png?P52AAb=gDsyT4foW&nwGCdNH=oMV HTTP/1.1" 403 571 "http://www.zashitimsa_ot_ddos.ru/hmcHaC?S7yLL=6S5wMd0gLqeU7pDVJhju&AIkWBRq7s=NRXF2LkivYBU85dCGa&Q3VhbAts=36R3Ybw&WagrK7x=eE4CAB5AbALM&3yY=GI8vgaCLa2BapE2&bkSLGi=2jVjFgDSdwtxj&EWWCesCSDc=P2qu&5djUfS=Yfin7q3t2UsPN8rbx" "Mozilla/5.0 (compatible; MSIE 7.0; MJ12bot; .NET CLR 3.0.27172; Intel Mac OS X 11_1_0)"
62.109.28.95 - - [07/Feb/2022:06:27:41 +0000] "GET /test.png?grw=txjgo&XSrbd=mbcJAf2diPBOxh&mLl=OGunDrcoWkhP HTTP/1.1" 403 571 "-" "Mozilla/5.0 (MJ12bot; Intel Mac OS X 11_3_3) AppleWebKit/535.35 (KHTML, like Gecko) Chrome/29.0.1227.45 Safari/537.7"
62.109.28.95 - - [07/Feb/2022:06:27:41 +0000] "GET /test.png?XmqsKdXD4p=JXm&Ehm=DofRoOaWIHukWIYHWbbo HTTP/1.1" 403 169 "-" "Mozilla/5.0 (MJ12bot; Intel Mac OS X 10_0_1) Gecko/20082911 Firefox/23.0"
62.109.28.95 - - [07/Feb/2022:06:27:41 +0000] "GET /test.png?hcFy=3jiNPtYiL&G0ctkasjSP=qHebQoiF&FkPPo=0lrX0QyRq05tqmqBO2P5&iH1YlUT=1KkpEb4on0Ef HTTP/1.1" 403 140 "http://www.bing.com/7kLfQh" "Mozilla/5.0 (MJ12bot; Intel Mac OS X 11_3_3) Gecko/20091607 Firefox/16.0"
62.109.28.95 - - [07/Feb/2022:06:27:41 +0000] "GET /test.png?hfiKSAITuR=qMl5GqfT6dim&AAdUx2=GKs HTTP/1.1" 403 199 "http://www.bing.com/FN2DCyTle" "Mozilla/5.0 (MJ12bot; Intel Mac OS X 11_7_5) AppleWebKit/535.27 (KHTML, like Gecko) Chrome/28.0.633.27 Safari/536.36"
62.109.28.95 - - [07/Feb/2022:06:27:41 +0000] "GET /test.png?EoJFcrq=DX53dVcC7U&7fx=Pwimtil50F5gYyR1d7 HTTP/1.1" 403 571 "http://www.bing.com/yPulwdB8S" "Mozilla/5.0 (compatible; MSIE 7.0b; MJ12bot; .NET CLR 3.0.27172; Intel Mac OS X 11_3_3)"

Шаг третий ‘fail2ban’

Пришло время для настройки отличного инструмента для защиты сервера и вашего продукта от вредоносного помешательства - fail2ban. Суть его работы такова, что он анализирует logs файлы запущенных программ и на основании выставленных условий производит блокировку IP-адреса на указанный промежуток времени.

1. Производим его установку на сервер

apt install fail2ban

2. Время настройки!

Копируем стандартный jail.conf и сохраняем его в jail.local:

cp /etc/fail2ban/jail.conf /etc/fail2ban/jail.local

После чего редактируем jail.local:

nano /etc/fail2ban/jail.local

И вставляем в конце jail.local. Конфигурация:

[nginx-limit-req]
enabled = true
filter  = nginx-limit-req
port    = http,https
logpath = /var/log/nginx/*error.log
findetime = 600
bantime = 600
maxretry = 5

Где:

enabled = true   /// включить фильтр
filter  = nginx-limit-req   /// название фильтра ‘nginx-limit-req’
port    = http,https   // название портов в данном случае 80 и 443
logpath = /var/log/nginx/*error.log   /// откуда парсить логи
findetime = 600   /// интервал в секундах, за которое событие должно повториться определённое количество раз
bantime = 600   /// время бана в секундах
maxretry = 5   /// количество повторений сообщения об ошибках
p.s. Не забываем!

Не забываем удалить повторяющиеся уже настройки данного фильтра в самой конфигурации иначе fail2ban не сможет перечитать конфиг и будет ругаться на ошибки.

3. Перезапускаем fail2ban и проверяем результат

fail2ban-client reload

Либо сделать restart сервиса:

systemctl restart fail2ban

Проверяем, что наш фильтр запущен:

fail2ban-client status nginx-limit-req
Status for the jail: nginx-limit-req
|- Filter
|  |- Currently failed: 0
|  |- Total failed:     0
|  `- File list:        /var/log/nginx/error.log
`- Actions
   |- Currently banned: 0
   |- Total banned:     0
   `- Banned IP list:

Результат:

В дальнейшем, когда запросы будут идти в Nginx, наш настроенный выше ‘rate’ будет писать сообщения об ошибках в /var/log/nginx/error.log.

Пример ответа из logs файлов:

2022/02/07 07:12:23 [error] 981#981: *203984 limiting requests, excess: 0.600 by zone "shield", client: 62.109.28.95, server: www.zashitimsa_ot_ddos.ru, request: "GET /test.png?ahcBAmSMG6=82a5yFHKiohqnB&AX4tIBX=msA50EPwJD7dB0eTabXe&RHxTyKgc=JBej4S5EGgeJDDA&TRGxNTpkq=AjtnEu&7rhhe=k6BW4UpFcmmNH8bC7N5 HTTP/1.1", host: "www.zashitimsa_ot_ddos.ru", referrer: "http://www.baidu.com/cxikKmt0?yonyA=TixYYDnOAG3XlORl&JdL4yV0iQ=7ep5APklt"

После этого в /var/log/fail2ban.log будет выведено сообщение о блокировке нашего подозрительного IP:

2022-02-07 07:14:22,208 fail2ban.actions        [3066]: NOTICE  [nginx-limit-req] Ban 62.109.28.95

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

Шаг четвертый ‘geoip’

Если вы прекрасно знакомы со своей аудиторией и знаете из каких стран вы желаете видеть пользователей, то для решения этой задачи отлично подойдет модуль, способный производить отсеивание и блокировку нежелательного трафика по геолокации IP адреса.

Если ранее у нас уже был установлен Nginx, то для работы с geiop нам потребуется собрать модуль из исходников и подключить его.

1. Производим установку на сервер необходимых библиотек.

add-apt-repository ppa:maxmind/ppa
apt update
apt install libmaxminddb0 libmaxminddb-dev mmdb-bin

2. Компилируем модуль под нужную версию Nginx, у нас это будет 1.18.0

cd /root
wget http://nginx.org/download/nginx-1.18.0.tar.gz
git clone https://github.com/leev/ngx_http_geoip2_module.git
tar zxvf nginx-1.18.0.tar.gz
cd nginx-1.18.0
./configure --with-compat --add-dynamic-module=../ngx_http_geoip2_module
make modules

3. Кладём его в наш каталог

mkdir -p /etc/nginx/modules
cp -vi objs/ngx_http_geoip2_module.so /etc/nginx/modules/

4. Скачиваем актуальные БД с IP адресами:

mkdir /etc/nginx/geoip ; cd /etc/nginx/geoip ; wget https://git.io/GeoLite2-Country.mmdb

5. После чего редактируем nginx.conf:

nano /etc/nginx/nginx.conf

И вставляем в блок http следующую мапу. Конфигурация:

load_module modules/ngx_http_geoip2_module.so;

...

http { 

        geoip2 /etc/nginx/geoip/GeoLite2-Country.mmdb {                                                                                                                                                                                                                         
          $geoip2_data_country_iso_code country iso_code;                                                                                                                                                                                                                      
       }

        map $geoip2_data_country_iso_code $is_deny {                                                                                                                                                                                                                                                                                                                                                                                                                                                               
           default no; # Запрещаем всем
           RU yes; # Разрешаем России
	    UK yes; # Разрешаем Великобритании
       }


}

6. Добавляем код location в наш виртуальный хост, как это делалось ранее. Конфигурация:

limit_req_zone $binary_remote_addr zone=shield:10m rate=1r/s

server {
       listen 80 ;

       root /var/www/html;

       server_name www.zashitimsa_ot_ddos.ru;

       
      if ( $http_user_agent ~* (bingbot|AhrefsBot|Ruby|PetalBot|SemrushBot|MJ12bot) ){
               return 403;
       }

      if ($allowed_country = no) {
          return 403;
      }

       location / {
              limit_req zone=shield;
               try_files $uri $uri/ =404;
       }

}

7. Посылаем команду нашему любимому Nginx на перечитку конфигураций и проверяем результат.

nginx -s reload

Если вы хотите узнать более подробную информацию про сборку динамических модулей, то вы можете ознакомиться со статьёй написанной ранее нашим DevOps Engineer.


Итог: “У каждого поколения должна быть своя война.” - Мао Цзэдун

Нельзя не заметить, что данная статья повествует о различных способах защиты от dos, но остаётся главный вопрос, который, я уверен, за время чтения уже был задан не однократно: “Как защититься от ddos?”. Ведь высококачественная атака, использующая большое количество IP-адресов может с лёгкостью обойти все уровни защиты, выставленные нами ранее. В данном случае лучше всего помогают следующие средства, а именно платформы по предоставлению услуг защиты и спокойного сна: Cloudflare, Incapsula, Servicepipe,  DDoS-Guard и etc

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

Берегите свои площадки и не допускайте простоя! 

P.S.: Кстати, DevOps-инженерам и системным администраторам будет интересно заглянуть в телеграм-канал DevOps FM, присоединяйтесь)

Tags:
Hubs:
+15
Comments 33
Comments Comments 33

Articles

Information

Website
nixys.io
Registered
Founded
Employees
51–100 employees
Location
Россия
Representative
Vlada Grishkina-Makareva