+7 (800) 333-17-63

Защита от DDoS-атак с помощью Nginx

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

Обложка статьи: Защита от DDoS-атак с помощью Nginx

Что такое Nginx

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

Схема работы Nginx — иллюстрация DDoS-Guard
Схема работы Nginx

Сервер Nginx популярен во всем мире и используется крупными компаниями, включая Netflix, ВКонтакте, 2ГИС, WordPress и другими. Также Nginx является ключевым компонентом многих технологических стеков, используемых в веб-разработке и веб-хостинге. Один из распространенных способов применения — в качестве веб-сервера для размещения сайта. 

Помимо этого, Nginx обладает рядом функций, которые пользователи могут использовать для защиты своего веб-ресурса от DDoS-атак:

  1. Ограничение скорости запросов. Поможет снизить нагрузку на сервер и предотвратить DDoS-атаки, основанные на отправке большого количества запросов от одного и того же источника.
  2. Балансировка нагрузки. Распределит нагрузку между несколькими серверами и поможет снизить риск отказа всей системы при атаке на один сервер.
  3. Отказ от подключения. Способствует предотвращению DDoS-атак, которые основаны на установлении большого количества подключений к серверу.
  4. Сокращение времени соединения. Закроет неактивные соединения и снизит риск DDoS-атак, основанных на удержании открытых соединений.
  5. Управление буферизацией. Минимизирует риск DDoS-атак, основанных на отправке больших объемов данных.

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

Все перечисленные функции помогают использовать Nginx в качестве средства для борьбы со многими видами DDoS-атак, однако для полноценной защиты от них стоит использовать профессиональные anti-DDoS решения.

Как защититься от DDoS-атак с помощью Nginx

1. Ограничение скорости обработки запросов

Для ограничения обработки запросов Nginx использует алгоритм под названием «дырявое ведро» (англ.«leaky bucket»). В данном случае ведро — это буфер, который имеет ограниченную емкость. Когда запросы поступают на сервер, они добавляются в ведро. Затем, запросы обрабатываются с определенной скоростью, не превышающей предел обработки сервера. Это один из методов управления трафиком, который можно использовать для защиты от DDoS-атак и обеспечения стабильной обработки запросов на сервере.

Чтобы настроить ограничение скорости, следует использовать две основные директивы: limit_req_zone и limit_req.

Директива limit_req_zone используется для создания зоны ddos_limit, в которой будет храниться информация о запросах от каждого уникального IP-адреса. Размер зоны определяется параметром 10m, что означает использование 10 мегабайт памяти для хранения информации о запросах. Пример:

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

server {
   location /login/ {
       limit_req zone=mylimit;
       
       proxy_pass http://my_upstream;
   }
}

В данном примере $binary_remote_addr используется для идентификации клиентского IP-адреса, который является ключом в зоне ограничения. Зона будет использоваться для ограничения скорости запросов до 10 запросов в секунду (10r/s). Далее с помощью директивы server { ... } определяется блок настроек для конкретного сервера. Ограничение запросов будет регулировать location /login/ { ... }
Внутри указанной локации mylimit директива limit_req zone=mylimit активирует ограничение запросов для зоны. Она регулирует запросы к URL-адресам. Все, которые начинаются с «/login/» — будут ограничены в соответствии с настройками.

Директива proxy_pass http://my_upstream — задает прокси-сервер, на который будут идти запросы после прохождения ограничения. В примере запросы будут передаваться на «my_upstream», — здесь следует указать реальный адрес сервера-приемника. 

2. Балансировка нагрузки

Nginx в качестве прокси-сервера может использовать базовую конфигурацию для балансировки нагрузки между несколькими серверами. Пример конфигурации:

http {
   upstream myapp1 {
       server srv1.example.com;
       server srv2.example.com;
       server srv3.example.com;
   }

   server {
       listen 80;

       location / {
           proxy_pass http://myapp1;
       }
   }
}

В этом примере на служебных записях DNS srv1, srv2 и srv3 запущены 3 экземпляра одного и того же приложения. Без настройки данный метод балансировки будет по умолчанию использовать циклический перебор. Nginx использует балансировку нагрузки HTTP для распределения запросов, которые проксируются к группе серверов myapp1. Чтобы реализовать обратное прокси в nginx, следует настроить балансировку для HTTPS вместо HTTP. Для этого в качестве протокола используйте «https».

3. Отказ от подключения

Для ограничения количества одновременных подключений в Nginx можно использовать директиву limit_conn. Она позволяет задать лимиты не только к определенному серверу, но и контексту. Пример полной конфигурации для ограничения количества одновременных подключений:

upstream api_service {
   server 127.0.0.1:9051;
   server 10.1.1.77:9052;
}
limit_conn_zone $binary_remote_addr zone=limitconnbyaddr:20m;
limit_conn_status 429;

server {
   listen 80;
   server_name testapp.tecmint.com;
   root /var/www/html/testapp.tecmint.com/build;
   index index.html;

   limit_conn   limitconnbyaddr  50;

   #include snippets/error_pages.conf;
   proxy_read_timeout 600;
   proxy_connect_timeout 600;
   proxy_send_timeout 600;
   location / {
       try_files $uri $uri/ /index.html =404 =403 =500;
   }
   location /api {
       proxy_pass http://api_service;

       proxy_set_header X-Real-IP $remote_addr;
       proxy_set_header Host $host;
       proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
       
       proxy_http_version 1.1;
       proxy_set_header Upgrade $http_upgrade;
       proxy_set_header Connection "upgrade";
  }
}

В этом примере была использована директива limit_conn_zone для создания зоны ограничения подключений с именем conn_limit_per_ip. Для этого используется переменная $binary_remote_addr, чтобы идентифицировать каждый уникальный IP-адрес, который подключается к серверу.

Затем следует задать ограничение с помощью директивы limit_conn, где будет указано имя зоны conn_limit_per_ip и максимальное количество одновременных подключений, равное 10.

С помощью директив задаем ограничение на количество одновременных подключений к серверу. Если количество подключений превышает заданный лимит, то Nginx будет возвращать ошибку 503 «Service Unavailable» клиентам, которые пытаются подключиться к серверу.

4. Сокращение времени соединения

Для сокращения времени соединения в Nginx есть несколько директив и конфигураций. Рассмотрим три из них — включение keep-alive соединений, сжатие и кэширование.

Включение keep-alive соединений

Keep-alive соединения позволяют клиенту и серверу устанавливать одно TCP-соединение и использовать его для множества последовательных HTTP-запросов и ответов вместо установки нового соединения для каждого запроса. Это значительно улучшает производительность и уменьшает нагрузку на сервер.

Рассмотрим одну из директив, которая определяет время ожидания соединения keep-alive между Nginx и клиентом — keepalive_timeout. Директива устанавливает время в секундах, в течение которого соединение keep-alive может оставаться открытым, ожидая новых запросов от клиента. Если в течение этого времени не было нового запроса, соединение будет закрыто. 
Пример использования:

http {
   ...
   
   keepalive_timeout 60s;
}
 

В данном примере, keepalive_timeout установлен в 60 секунд. Это означает, что соединение keep-alive может оставаться открытым в течение 60 секунд после последнего запроса от клиента.

Значение keepalive_timeout следует выбирать с учетом потребностей вашего приложения и среды. Слишком короткое время тайм-аута приводит к частым закрытиям и повторным установкам соединений, что может увеличить нагрузку на сервер.

Важно отметить, что конфигурация keep-alive может различаться в зависимости от требований вашего приложения, версии Nginx и других факторов. Рекомендуется ознакомиться с документацией Nginx и учесть специфику вашей среды перед применением конфигурации.

Включение сжатия

Nginx по умолчанию сжимает запросы типа text/html. Сжатие позволяет уменьшить размер передаваемых данных, что существенно ускоряет их передачу и сокращает время соединения. Пример конфигурации:

server {
   gzip on;
   gzip_types text/plain application/xml;
   gzip_proxied no-cache no-store private expired auth;
   gzip_min_length 1000;
   ...
}
 

Эта директива имеет ряд параметров, которые определяют, какие типы прокси-запросов Nginx следует сжимать. Например, ее можно настроить таким образом, чтобы сжимались только те ответы на запросы, которые не будут кэшироваться на прокси-сервере. Для этого используйте параметры директивы gzip_proxied, которые будут проверять Cache-Control поле заголовка в ответе и сжимать ответ, если значение равно no-cache, no-store или private.

Помимо этого важно включить параметр expired для проверки значения поля заголовка Expires. Чтобы настроить возможность сжатия других типов прокси-запросов, включите директиву gzip_types и перечислите их. Чтобы указать минимальную длину ответа для сжатия, используйте директиву gzip_min_length. Значение по умолчанию равно 20 байтам (в примере конфигурации скорректировано на 1000). Используйте gzip_proxied для настройки сжатия прокси-запросов.

Использование кэширования

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

proxy_cache_path /data/nginx/cache keys_zone=cache_zone:10m;

map $request_method $purge_method {
   PURGE   1;
   default 0;
}

server {
   ...
   location / {
       proxy_pass http://backend;
       proxy_cache cache_zone;
       proxy_cache_key $uri;
       proxy_cache_purge $purge_method;
   }
}

Для этого примера была использована директива proxy_cache_path для создания кэша статических ресурсов. Чтобы задать размер кэша вводим keys_zone=static_cache:10m, он должен быть равен 10 мегабайтам. Переменная $purge_method сбрасывает кэш и по умолчанию равна нулю. Таким образом Nginx работает в обычном режиме и сохраняет ответы от бэкенда. Если метод запроса — «PURGE», переменной будет присвоено значение «1», в противном случае — «0». Proxy_cache_purge $purge_method; указывает на то, что кэш должен быть очищен при выполнении запроса с методом «PURGE». Значение переменной $purge_method определяет, является ли текущий запрос запросом на очистку кэша или нет.

5. Управление буферизацией

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

  • Чтобы отключить буферизацию в Nginx используйте директиву proxy_buffering с параметром off.
  • Чтобы настроить размер буфера для проксируемых ответов от сервера используйте директиву proxy_buffer_size. По умолчанию значение proxy_buffer_size равно 4K или 8K, в зависимости от версии Nginx и используемого модуля проксирования. Однако, вы можете изменить это значение в соответствии с вашими требованиями. Чтобы избежать частой ошибки «502 Bad Gateway» — значение для proxy_buffer_size должно быть не меньше максимально возможного размера HTTP-заголовков ответа, которые поступают из вашего веб-ресурса.

Веб-серверы сами по себе не являются средствами защиты от вредоносного трафика. Однако их инструменты и программные решения могут помочь в предотвращении или смягчении последствий DDoS-атак. В следующих статьях рассмотрим защитные решения по настройке Apache, Lighttpd и других серверов.

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

Читайте в телеграм-канале DDoS-Guard

Анонсы, статьи, истории и советы по кибербезопасности. Каждый месяц собираем дайджест о самых громких событиях

Подписаться