Home » Linux » Защита web сервера от программ для ddos атак

Защита web сервера от программ для ddos атак

Некоторое время назад я написал подробную статью про установку и настройку web сервера на базе nginx и php-fpm последних версий. Там я упомянул, что это первая статья из цикла заметок о веб сервере. Сегодня я расскажу как простыми и подручными средствами защититься от простых ddos атак.

Если у вас есть желание научиться администрировать системы на базе Linux, рекомендую познакомиться с онлайн-курсом «Linux для начинающих» в OTUS. Курс для новичков, для тех, кто с Linux не знаком. Подробная информация.

Введение

Сразу сделаю оговорку по поводу слова ddos, которое тут не совсем уместно, но я не придумал, как еще популярно объяснить о чем идет речь. От полноценной ddos атаки вы не сможете защититься в рамках настройки веб сервера. У вас просто будет забит весь канал и сервер перестанет отвечать. Если мощности сервера не достаточно для обработки и фильтрации входящих запросов, то он ляжет, чтобы вы там не делали. Для полноценной защиты от ddos нужны полноценные средства, которые стоят ощутимых финансовых затрат. Более подробно с теорией по защите от ddos читайте в отдельной статье.

Нужно понимать, что защита от ddos должна быть адекватна значимости ресурса. Если у вас персональный блог, который не приносит существенной прибыли, то платить за защиту от ddos бессмысленно. Достаточно просто полежать какое-то время или сделать защиту своими силами. В общем, всегда нужно соизмерять стоимость простоя со стоимостью защиты и на основе этого принимать решение о целесообразности того или иного метода.

Я приведу советы по защите от простых атак ботов или каких-то мелких вредителей и пакостников, которые без должных действий с вашей стороны могут положить ваш сайт или сервер без особых проблем. Вот простой пример. Есть не очень слабый виртуальный сервер от ihor, на борту которого 2 ярда, 8 гигов оперативы и ssd диск.

Сервер настроен по моей предыдущей статье, ссылку на которую привел в начале. На сервере развернут wordpress сайт с некоторым содержимым. И есть у нас вредитель, который на своем сервере запускает простой тест от apache на производительность веб сервера:

# ab -c 50 -n 30000 "https://hl.zeroxzed.ru/"

Всего лишь 50 параллельных потоков. Что мы видим на своем веб сервере:

Нагрузка на сервер от ddos

Не очень приятная картина. Сервер загружен на 100%. И хотя он нормально обрабатывает запросы и в целом корректно работает. Даже не очень тормозит, но все равно это плохо. А если будет 3 сервера и по 100 потоков на каждом? Нет никаких проблем даже на тест взять у разных хостеров по виртуальной машине и запускать на них подобные штуки, имитируя ддос атаку.

В общем, если вы совсем не сделали никакой защиты на своем сервере, то любой человек сможет вам без особых проблем доставить некоторые неудобства. Защититься от такой "атаки" не сложно. Дальше я расскажу как это сделать.

Защита от ddos с помощью iptables

Для защиты от простейшей атаки мы будем использовать firewall - iptables, модуль ядра ipset для хранения больших списков ip и самописные скрипты. По фаерволу смотрите мою статью - настройка iptables. Здесь я не буду на этом останавливаться.

Вопрос настройки ipset я подробно рассматривал в своей статье по блокировке ботов по странам. Советую посмотреть материал, так как он напрямую связан с этой статьей и дополняет ее.

Итак, приступим к созданию нашей простой защиты от dos атаки с большим количеством подключений с одного ip адреса. Для начала проверим команду, которая покажет нам количество подключений с каждого ip адреса:

# netstat -ntu | awk '{print $5}' | grep -vE "(Address|servers|127.0.0.1)" | cut -d: -f1 | sort | uniq -c | sort -n| sed 's/^[ \t]*//'

Список активных подключений к серверу

У меня получается примерно так. Много единичных подключений. Идет штатная работа веб сервера, никто на него не ломится десятками подключений. Теперь нагрузим наш сервер множественными паразитными запросами и еще раз посмотрим вывод команды.

Выявление активного бота

Вот он, нарушитель нашего спокойствия, пытающийся организовать дос атаку на наш сервер. Теперь нарисуем скрипт, который будет блокировать всех кто устанавливает более 50-ти одновременных соединений с сайтом.

#!/bin/sh

netstat -ntu | awk '{print $5}' | grep -vE "(Address|servers|127.0.0.1)" | cut -d: -f1 | sort | uniq -c | sort -n| sed 's/^[ \t]*//' | awk '{if ($1 > 50 ) print$2}' > /root/ddos/much_conn.txt

sleep 3

list=$(cat /root/ddos/much_conn.txt)
for ipnet in $list
    do
	ipset -A much_conn $ipnet
    done

В принципе, комментировать тут особо нечего. Берем список подключений, который только что вывели, в нем сравниваем первую колонку, если она больше 50, то результат второй колонки, где записан ip адрес, передаем в файл.

Далее читаем этот файл и добавляем все ip адреса из него в ipset список под названием much_conn. Предварительно его надо создать. Подробно об этом я рассказывал в статье, на которую привел ссылку выше, но повторю еще раз здесь:

# ipset -N much_conn iphash

Посмотреть содержимое списка можно командой:

# ipset -L much_conn

Теперь нужно добавить в iptables правило, по которому будут блокироваться все подключения из указанного списка ipset.

# iptables -A INPUT -m set --match-set much_conn src -j DROP
На всякий случай предупреждаю, чтобы вы проверили свой доступ к консоли сервера, прежде чем настраивать правила iptables. Всякое бывает, можно просто ошибиться, скопировать и вставить не то, что нужно.

Все, мы заблокировали всех, кто создает массовый спам подключений к серверу. Ограничение в 50 подключений можете исправлять по месту, возможно его нужно будет уменьшить, если кто-то будет открывать меньше подключений с одного ip.

Единственный момент, о котором хочу сказать. Сам я не проверял, сколько подключений открывают поисковые боты, когда приходят на сайт. Я подозреваю, что явно не 50 и даже не 30, но наверняка я не проверял. В общем, будьте аккуратны, когда используете это средство.

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

Было бы неплохо как-то автоматически очищать список забаненных, удаляя оттуда тех, кто уже сутки к вам не подключается, но это сильно усложняет задачу. Нужно как минимум вести лог по блокирующему списку, сохранять время последнего обращения. Обрабатывать все это, высчитывать. В общем, задача хоть и не сильно сложная, но уже не тривиальная. Мне не захотелось этим заниматься.

Есть хоть и не очень изящное, но простое решение этой проблемы. Создать список ipset с заданным временем жизни записи с помощью timeout. Например вот так:

ipset -N much_conn iphash timeout 3600

В данном случае запись с забаненным ip в списке ipset будет храниться в течении 3600 секунд или 60 минут.

Нужно понимать, что в данном примере с 1 ip адресом использовать ipset нет никакого смысла, можно сразу банить средствами самого iptables. Ipset нужен только тогда, когда этот список хотя бы в сотни строк. Если там несколько десяткой адресов, хватит и одного iptables.

Анализ лог файла web сервера для защиты от ddos

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

Банить будем тоже через iptables, а список адресов для бана будем извлекать из логов веб сервера. Для этого у вас должно быть включено логирование запросов к веб серверу. Например, в nginx за это отвечает такая настройка виртуального хоста:

access_log /web/sites/hl.zeroxzed.ru/log/access.log main;

Мы не будем каждый раз анализировать весь лог файл. Эта операция сама по себе будет сильно нагружать веб сервер. Возьмем последние 1000 строк из лог файла и посчитаем количество подключений с одного ip с типовым содержимым, например запрос главной страницы по протоколу http 1.0, "GET / HTTP/1.0". Если вы заметите другой постоянный признак ботнета, который вас атакует, используйте его. Это может быть один и тот же user agent или что-то еще. Допустим, если атакующий будет долбить в уязвимое место, то это будет адрес этой страницы.

# tail -1000 /web/sites/hl.zeroxzed.ru/log/ssl-access.log | egrep "GET / HTTP/1.0" | awk '{print $1}' | sort -n | uniq -c

Результатом этой команды будет примерно такой список.

Поиск ботов на основе лога вебсервера

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

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

#!/bin/sh

tail -1000 /web/sites/hl.zeroxzed.ru/log/ssl-access.log | egrep "GET / HTTP/1.0" | awk '{print $1}' | sort -n | uniq -c | sort -n | tail -n100 | awk '{if ($1 > 50 ) print $2}' > /root/ddos/much_gets.txt

sleep 3

list=$(cat /root/ddos/much_gets.txt)
for ipnet in $list
    do
	ipset -A much_gets $ipnet
    done

Здесь делаем то же самое, что и раньше. Те, кто сделали более 50-ти одинаковых запросов по нашей маске на последние 1000 строк в лог файле, отправляются в бан.

Обращаю внимание на строку, по которой вы будете фильтровать запросы. В данном случае я показал только пример. Не надо брать и применять в том виде, как я показываю. Я демонстрирую технические возможности и подход. Настраивать и калибровать систему вам нужно у себя по месту. Важно это понимать и не применять решение бездумно. Будет только вред.

Не забудьте создать отдельный список в ipset и добавить отдельное правило в ipables. Можно использовать уже существующий список и добавленное правило из предыдущего примера, но я рекомендую все разделять. Так удобнее для последующего анализа.

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

Баним ботов с неправильным referer

Есть категория простых ботов, которые подставляют в referrer либо мусор, либо кривые урлы без http или https в начале. Например вот такие:

194.67.215.242 - - [30/Nov/2017:20:48:08 +0300] "POST /index.php HTTP/1.1" 200 913 "g0dfw4p1.ru" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" "-"

Корректное поле referer должно содержать либо http, либо https, либо быть пустым. Все, что иначе, можно смело блокировать или возвращать статус ошибки. Добавляем примерно такую конструкцию в конфигурацию виртуального хоста, в раздел server {}.

if ($http_referer !~* ^($|http://|https://) ) {
return 403;
}

После этого проверьте конфигурацию nginx и перечитайте ее.

# nginxt -t
# nginx -s reload

Если вас достает какой-то бот с конкретным referer, можно забанить именно его. Для этого можно дополнить условие, или изменить. Например, вот так:

if ($http_referer = "https://bots.ru/dostanim_tebya.html") {
return 403;
}

В дополнение, можно всех этих ботов с помощью простого скрипта банить на iptables, как в примерах выше. К слову сказать, их можно банить сразу, разбирая http запросы еще до того, как они будут попадать к nginx, например, с помощью ngrep, но это более сложная задача. Не все это умеют делать, там есть нюансы, а с nginx знакомы все. Не составит большого труда реализовать данный метод.

Защита от ддос с помощью модулей nginx - limit_conn и limit_req

Поделюсь еще одним простым способом снизить нагрузку на сервер и частично защититься от ддос с помощью модулей nginx - limit_conn и limit_req. Настроить их не сложно, частично результат работы первого модуля будет пересекаться с первыми двумя способами ddos защиты, описанными в начале. Он более простой для настройки, так что если не справились с теми способами, можно попробовать этот.

Смысл данных модулей в том, что один может ограничить одновременное количество разрешенных соединений с сайтом, а другой количество соединений в единицу времени.

Я ограничу в своем примере количество одновременных подключений к сайту с одного ip числом 50, а количество одновременных запросов к динамическому контенту не более 2-х в секунду. При этом будет разрешен всплеск (burst) запросов до 5-ти. Объясню, как понимать этот всплеск, так как сам не сразу понял, что конкретно он означает.

Если у нас идет превышение количества установленных запросов в секунду, то их выполнение задерживается, и они выстраиваются в очередь на исполнение с указанной скоростью. Размер этой очереди и равен значению всплеска. Все запросы, которым не хватит места в очереди, будут завершены с ошибкой.  То есть, если запросов будет 4 в секунду, то 2 выполнятся сразу и еще 2 встанут в очередь. А если будет 10, то 2 выполнятся сразу, 5 встанут в очередь на выполнение по 2 штуки в секунду, а остальные будут завершены с ошибкой.

Исходя из этих условий, ограничение на подключения нужно установить в контексте server, а на доступ к динамическому контенту в соответствующем location. При этом описание зон, которые будут использовать директивы, нужно расположить в http.

Вот пример конфига nginx для реализации установленных ограничений с целью защиты от ддос атак.

http {
      ...
      limit_conn_zone $binary_remote_addr zone=perip:10m;
      limit_req_zone $binary_remote_addr zone=dynamic:10m rate=2r/s;
      ...
      server {
              ...
              limit_conn perip 50;
              ...
              location ~ \.php$ {
                                 ...
                                 limit_req zone=dynamic burst=5 nodelay;
                                 ...
              }
      }
}

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

Ошибка сервера при отражении ддоса

и запись в логе с ошибками:

2017/11/30 15:25:26 [error] 9773#9773: *51482 limiting requests, excess: 5.664 by zone "dynamic", client: 195.91.248.43, server: hl.zeroxzed.ru, request: "GET / HTTP/2.0", host: "hl.zeroxzed.ru", referrer: "https://hl.zeroxzed.ru/2013/03/15/featured-image-vertical/"

Лимит на количество подключений можете проверить той же утилитой ab, о которой я рассказал во введении.

017/11/30 15:38:56 [error] 9773#9773: *53938 limiting connections by zone "perip", client: 94.142.141.246, server: hl.zeroxzed.ru, request: "GET /wp-content/uploads/2013/03/the-dark-knight-rises.jpg HTTP/1.0", host: "hl.zeroxzed.ru"

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

При выставлении ограничений, не забудьте проконтролировать, не попадают ли в эти ограничения поисковые боты. По-умолчанию, они стараются не создавать повышенную нагрузку на сайт. При желании, роботу яндекса можно указать через robots.txt, с какой скоростью сканировать ваш сайт. А роботу гугла то же самое можно сделать через webmaster.

Заключение

Не понравилась статья и хочешь научить меня администрировать? Пожалуйста, я люблю учиться. Комментарии в твоем распоряжении. Расскажи, как сделать правильно!

Я рассмотрел наиболее простые способы для защиты web сервера от не менее простых ddos атак, которые больше похожи на баловство. Серьезная атака, которая просто зальет весь входящий канал сервера, даже не заметит наших защит. Но тем не менее, мне приходилось убеждаться в эффективности этих способов в отражении некоторых атак.

Существует до сих пор огромное количество веб серверов, которые вообще никак не защищены даже от утилиты ab :) Я знаю о чем говорю, так как мне попадаются в работу такие серверы. И есть так же много всяких ботов и простых программ, которые можно найти на просторах интернета и побаловаться, заваливая сайты, которые не готовы к нагрузкам вообще.

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

Суть защиты в том, что с помощью nginx выдаем пользователю определенную cookies, а потом редиректим на запрашиваемую страницу. Если бот не понимает кукисов или редиректов, то он отваливается. Нормальные пользователи ничего не замечают. Возможно позже я отдельно расскажу про этот способ и дополню статью. А пока все. Буду рад замечаниям по существу в статьях.

Если у вас есть желание научиться администрировать системы на базе Linux, но вы с ними никогда не работали и не знакомы, то рекомендую начать с онлайн-курса «Linux для начинающих» в OTUS. Курс для новичков, для тех, кто с Linux не знаком. Цена за курс минимальная (символическая). Информация о курсе и цене.

Помогла статья? Подписывайся на telegram канал автора

Анонсы всех статей, плюс много другой полезной и интересной информации, которая не попадает на сайт.

Автор Zerox

Владимир, системный администратор, автор сайта. Люблю настраивать сервера, изучать что-то новое, делиться знаниями, писать интересные и полезные статьи. Открыт к диалогу и сотрудничеству. Если вам интересно узнать обо мне побольше, то можете послушать интервью. Запись на моем канале - https://t.me/srv_admin/425 или на сайте в контактах.

11 комментариев

  1. if ($http_referer !~* ^($|http://|https://) ) {
    return 403;
    }

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

    • Почему не зайти. Реферер в таком случае будет пустой. А данное правило блокирует те реферерры, что существуют и начинаются не с http или https.

  2. Александр

    здравствуйте! Пустой файл после запуска скрипта

  3. Спасибо за статью!

    > Корректное поле referer должно содержать либо http, либо https, либо быть пустым. Все, что иначе, можно смело блокировать или возвращать статус ошибки.
    К сожалению, такая блокировка не пропускает, к примеру, следующий вполне валидный referer: android-app://com.google.android.gm
    Мы поймали его когда был переход по ссылке из приложения Gmail в Android.

    • Да, вы правы. Есть и еще другие варианты refferer. По этому признаку блокировать надо очень аккуратно.

  4. Спасибо за информации

  5. Спасибо за советы

  6. Спасибо за статью. Вчера читал о дополнительной защите от ddos на хабре, по этой теме будет думаю тоже интересено - https://habrahabr.ru/company/itsumma/blog/343328/

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

Добавить комментарий

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

Нажимая кнопку "Отправить комментарий" Я даю согласие на обработку персональных данных.
Используешь Telegram? Подпишись на канал автора →
This is default text for notification bar