Защита nginx от DDoS атак

Nginx Logo

Рассмотрим защиту веб-сервера ngix работающей на операционной системе Ubuntu (в принципе - любой Linux).

Существует два типа DoS/DDoS-атак основанных на идее флуда, то есть заваливания жертвы огромным количеством пакетов.

Флуд бывает разным: ICMP-флуд, SYN-флуд, UDP-флуд и HTTP-флуд. Современные DoS-боты могут использовать все эти атаки одновременно, поэтому следует заранее позаботиться об адекватной защите от каждой из них.

  • ICMP-флуд
  • Примитивный метод забивания полосы пропускания и создания нагрузок на сетевой стек через монотонную посылку запросов ICMP ECHO (пинг). Он обнаруживается с помощью анализа потоков трафика в обе стороны: во время атаки типа ICMP-флуд они практически идентичны. Практически безболезненный способ абсолютной защиты основан на отключении ответов на запросы ICMP ECHO:

    nano /etc/sysctl.conf

    Вставляем:

    net.ipv4.icmp_echo_ignore_all=1

    сохраним и применим:

    sudo sysctl -p
  • SYN-флуд

  • Один из распространенных способов не только забить канал связи, но и ввести сетевой стек операционной системы в такое состояние, когда он уже не сможет принимать новые запросы на подключение.
    Основан на попытке инициализации большого числа одновременных TCP-соединений через посылку SYN-пакета с несуществующим обратным адресом. После нескольких попыток отослать ответный ACK-пакет на недоступный адрес большинство систем ставят неустановленное соединение в очередь. И только после n-ой попытки закрывают соединение.
    Так как поток ACK-пакетов очень велик, вскоре очередь оказывается заполненной, и ядро дает отказ на попытки открыть новое соединение.
    Наиболее умные DoS-боты еще и анализируют систему перед началом атаки, чтобы слать запросы только на открытые жизненно важные порты. Идентифицировать такую атаку просто: достаточно попробовать подключиться к одному из сервисов.

    Оборонительные мероприятия обычно включают в себя:
    Увеличение очереди "полуоткрытых" TCP-соединений,
    Уменьшение времени удержания "полуоткрытых" соединений,
    Включение механизма TCP syncookies,
    Ограничение максимального числа "полуоткрытых» соединений с одного IP к конкретному порту"

    nano /etc/sysctl.conf
    net.ipv4.tcp_max_syn_backlog=2048

    net.ipv4.tcp_synack_retries=1

    net.ipv4.tcp_syncookies=1

    Применим:

    sudo sysctl -p

    Ограничение максимального числа "полуоткрытых" соединений с одного IP к конкретному порту:

    iptables -I INPUT -p tcp --syn --dport 80 -m iplimit --iplimit-above 10 -j DROP
  • UDP-флуд

  • Обычный метод захламления полосы пропускания. Основан на бесконечной посылке UDP-пакетов на порты различных UDP-сервисов. Легко устраняется за счет отрезания таких сервисов от внешнего мира и установки лимита на количество соединений в единицу времени к DNS-серверу на стороне шлюза:

    iptables -I INPUT -p udp --dport 53 -j DROP -m iplimit --iplimit-above 1

    Скорей всего придётся пересобрать ядро. Но это уже сами.......

  • HTTP-флуд

  • Один из самых популярных на сегодняшний день способов флуда. Основан на бесконечной посылке GET запросов на 80-ый порт с целью загрузить web-сервер настолько, чтобы он оказался не в состоянии обрабатывать все остальные запросы.
    Бывает, что целью флуда становится не корень web-сервера, а один из скриптов, выполняющих ресурсоемкие задачи или работающий с базой данных. В любом случае, индикатором начавшейся атаки будет служить аномально быстрый рост логов web-сервера.
    Методы борьбы с HTTP-флудом включают в себя настройку web-сервера и базы данных с целью снизить эффект от атаки, а также для отсеивания DoS-ботов с помощью различных приемов.

    Во-первых, следует увеличить максимальное число коннектов к базе данных одновременно.
    Во-вторых, установить перед web-сервером Apache легкий и производительный nginx – он будет кэшировать запросы и отдавать статику. Это решение из списка "must have", которое не только снизит эффект DoS-атак, но и позволит серверу выдержать огромные нагрузки.
    Например:

    nano /etc/nginx/nginx.conf
    # Увеличиваем максимальное количество используемых файлов
    worker_rlimit_nofile 8192;
    ## Число рабочих процессов, рекомендуется ставить по количеству ядер
    worker_processes 1;
    # Уменьшает число системных вызовов gettimeofday(), что приводит к увеличению производительности
    timer_resolution 100ms;
    # Директива задаёт приоритет рабочих процессов от -20 до 20 (отрицательное число означает более высокий приоритет).
    worker_priority -5;

    events {
    # Увеличиваем максимальное количество соединений
    worker_connections 2048;
    # Использовать эффективный метод epoll для обработки соединений
    use epoll;
    }
    http {
    # Включить sendfile(). Использование sendfile() экономит системные вызовы, уменьшает число копирований данных
    sendfile on;
    output_buffers 2 64k;

    gzip on;
    gzip_min_length 1100;
    gzip_buffers 64 8k;
    gzip_comp_level 3;
    gzip_http_version 1.1;
    gzip_proxied any;
    gzip_types text/plain application/xml application/x-javascript text/css;
    # Отключаем таймаут на закрытие keep-alive соединений
    keepalive_timeout 0;
    # Не отдавать версию nginx в заголовке ответа
    server_tokens off;
    # Сбрасывать соединение по таймауту
    reset_timedout_connection on;
    #Директива описывает зону, в которой хранятся состояния сессий. Значения сессий определяется заданной переменной.
    limit_req_zone $binary_remote_addr zone=one:10m rate=1r/s;

    }

    server {
    listen 80 default;
    server_name localhost;

    access_log /var/log/nginx/localhost.access.log;

    location / {
    root /var/www/;
    index index.html index.htm index.php;
    open_file_cache max=1024 inactive=600s;
    open_file_cache_valid 2000s;
    open_file_cache_min_uses 1;
    open_file_cache_errors on;
    }
    location ~ \.php$ {
    limit_req zone=one burst=5;
    fastcgi_pass unix://tmp/php5-fpm.sock;
    fastcgi_index index.php;
    fastcgi_param SCRIPT_FILENAME /var/www$fastcgi_script_name;
    include fastcgi_params;
    fastcgi_hide_header "Cache-Control";
    }
    location ~ /\.ht {
    deny all;
    }
    expires max; # Внимание!!! Эта строка expires необходима!
    add_header Last-Modified $sent_http_Expires;
    }


    В случае необходимости можно задействовать nginx-модуль ngx_http_limit_req_module, ограничивающий количество одновременных подключений с одного адреса. Ресурсоемкие скрипты можно защитить от ботов с помощью задержек, кнопок "Нажми меня", выставления кукисов и других приемов, направленных на проверку "человечности".

    Чтобы не попасть в безвыходное положение во время обрушения DDoS-шторма на системы, необходимо тщательным образом подготовить их к такой ситуации:

    1. Сервера, имеющие прямой доступ во внешнюю сеть, должны быть подготовлены к простому и быстрому удаленному ребуту (sshd спасет отца русской демократии). Большим плюсом будет наличие второго, административного, сетевого интерфейса, через который можно получить доступ к серверу в случае забитости основного канала.
    2. Программное обеспечение(ПО), используемое на сервере, всегда должно находиться в актуальном состоянии. Все дырки — пропатчены, обновления установлены (между прочим, простой совет, которому многие не следуют). Это оградит от DoS-атак, эксплуатирующих баги в сервисах.
    3. Все слушающие сетевые сервисы, предназначенные для административного использования, должны быть спрятаны брандмауэром ото всех, кто не должен иметь к ним доступ. Тогда атакующий не сможет использовать их для проведения DoS-атаки или брутфорса.
    4. На подходах к серверу (ближайшем маршрутизаторе) должна быть установлена система анализа трафика (NetFlow в помощь), которая позволит своевременно узнать о начинающейся атаке и вовремя принять меры по ее предотвращению.

    И снова:

    nano /etc/sysctl.conf

    Защита от спуфинга

    net.ipv4.conf.default.rp_filter = 1

    Проверять TCP-соединение каждую минуту. Если на другой стороне - легальная машина, она сразу ответит. Дефолтовое значение - 2 часа.

    net.ipv4.tcp_keepalive_time = 60

    Повторить пробу через десять секунд

    net.ipv4.tcp_keepalive_intvl = 10

    Количество проверок перед закрытием соединения

    net.ipv4.tcp_keepalive_probes = 5

    Сохраним, и применим:

    sudo sysctl -p

    И да, раз уж мы добрались до sysctl.conf, можно заодно выключить IPv6, ибо оно нам совсем не нужно.

    #disable ipv6
    net.ipv6.conf.all.disable_ipv6 = 1
    net.ipv6.conf.default.disable_ipv6 = 1
    net.ipv6.conf.lo.disable_ipv6 = 1
    sudo sysctl -p

    Все приемы, приведенные в этом топике, направлены на снижение эффективности DDoS-атак, ставящих своей целью израсходовать ресурсы машины.
    От флуда, забивающего канал мусором, защититься практически невозможно, и единственно правильный, но не всегда осуществимый способ борьбы заключается в том, чтобы "лишить атаку смысла".
    Если вы заимеешь в свое распоряжение действительно широкий канал, который легко пропустит трафик небольшого ботнета, то считай, что от 90% атак твой сервер защищен. Есть и более изощренный способ защиты.
    Он основан на организации распределенной вычислительной сети, включающей в себя множество дублирующих серверов, которые подключены к разным магистральным каналам.
    Когда вычислительные мощности или пропускная способность канала заканчиваются, все новые клиенты перенаправляются на другой сервер (или же постепенно "размазываются" по серверам по принципу round-robin).
    Это очень дорогая, но очень стойкая структура, завалить которую практически нереально.
    Ещё одно более-менее эффективное решение заключается в покупке дорогостоящих хардварных систем Cisco Traffic Anomaly Detector и Cisco Guard.
    Работая в связке, они могут подавить начинающуюся атаку, но, как и большинство других решений, основанных на обучении и анализе состояний, дают сбои.
    Поэтому следует подумать перед тем, как выбивать из начальства десятки тысячи баксов на такую защиту.

    "CENSORED, началось. Что делать?"

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

    Наличие SYN-флуда устанавливается легко - через подсчет числа "полуоткрытых" TCP-соединений:

    sudo netstat -na | grep ":80\ " | grep SYN_RCVD

    В обычной ситуации их не должно быть совсем (или очень небольшое количество: максимум 1-3). Если это не так - ты атакован, срочно переходи к "дропанью" атакующих.

    С HTTP-флудом несколько сложнее. Для начала нужно подсчитать количество процессов Apache и количество коннектов на 80-ый порт:

    ps aux | grep httpd | wc -l
    netstat -na | grep ":80\ " | wc -l

    Значения, в несколько раз превышающие среднестатистические, дают основания задуматься. Далее следует просмотреть список IP-адресов, с которых идут запросы на подключение:

    netstat -na | grep ":80\ " | sort | uniq -c | sort -nr | less

    Однозначно идентифицировать DoS-атаку нельзя, можно лишь подтвердить свои догадки о наличии таковой, если один адрес повторяется в списке слишком много раз (да и то, это может говорить о посетителях, сидящих за NAT'ом). Дополнительным подтверждением будет анализ пакетов с помощью tcpdump:

    tcpdump -n -i eth1 -s 0 -w output.txt dst port 80 and host IP-сервера

    Убедитесь в существовании интерфейса eth1. Проверить это просто - ifconfig. В случае чего замените на свой.

    Показателем служит большой поток однообразных (и не содержащих полезной информации) пакетов от разных IP, направленных на один порт/сервис (например, корень web-сервера или определенный cgi-скрипт).
    Окончательно определившись, начинаем дропать неугодных по IP-адресам (будет гораздо больше эффекта, если ты сделаешь это на маршрутизаторе):

    iptables -A INPUT -s xxx.xxx.xxx.xxx -p tcp --destination-port http -j DROP

    или метод извращенцев, по подсетям:

    iptables -A INPUT -s xxx.xxx.0.0/16 -p tcp --destination-port http -j DROP

    Это даст вам некоторую фору (совсем маленькую; зачастую IP-адрес источника спуфится), которую ты должен использовать для того, чтобы обратиться к провайдеру/хостеру (с приложенными к сообщению логами web-сервера, ядра, брандмауэра и списком выявленных тобой IP-адресов).
    Большинство из них, конечно, проигнорируют это сообщение (а хостинги с оплатой трафика еще и порадуются - DoS-атака принесет им прибыль) или просто отключат ваш сервер. Но в любом случае это следует сделать обязательно, – эффективная защита от DDoS возможна только на магистральных каналах. В одиночку ты справишься с мелкими нападками, направленными на истощение ресурсов сервера, но окажешься беззащитным перед более-менее серьезным DDoS'ом.

    Не нужно копировать всё отсюда и вставлять в конфиг. Проверьте сначала, может параметр уже определён, и его стоит просто переопределить. Например

    cat /etc/sysctl.conf |grep net.ipv6.conf.lo.disable_ipv6
    Оцените блог: 
    Средняя: 2.9 (191 оценка)

    Задать вопрос