В нашем блоге на Хабре мы пишем не только о развитии нашего облачного проекта 1cloud, но и рассказываем о том, как решать те или иные технологические задачи. Летом 2015 года в блоге проекта NGINX появился материал о том, как с его помощью можно противостоять DDoS-атакам. Заметка показалась нам интересной, поэтому мы приводим здесь ее основные моменты.
Введение: что такое DDoS
Distributed Denial of Service attack – «распределенная атака на сервис с целью его отказа от обслуживания» — это попытка сделать любой сервис, обычно веб-сайт, недоступным, путем бомбардировки его трафиком из множества источников. В итоге сервер, его обслуживающий, просто перестает нормально работать, не справляясь с перегрузками.
Стандартная схема в этом деле – «замучить» систему таким количеством новых соединений и запросов, чтобы сеть перестала справляться с их потоком, или стала настолько медленной, что с ней невозможно работать.
Технические характеристики DDoS-атаки
На прикладном уровне DDoS-атака производится специальными программами (ботами), которые могут использовать уязвимости в конкретной системе. Например, система, которая не заточена под управление большим числом параллельных соединений, может быть выведена из строя путем создания большого числа таких «коннектов». В активном состоянии их можно поддерживать, время от времени засылая через них небольшие объемы трафика. Другой вариант – заваливать систему большим количеством запросов или делать эти запросы достаточно тяжелыми. Речь ведь идет не об актуальных соединениях, поэтому через боты очень легко отправлять огромное число запросов и быстро создавать множество новых соединений.
Ниже приведены технические характеристики DDoS-атак, по которым их можно распознать, и, учитывая которые, с ними справиться:
- Трафик обычно идет с фиксированного числа IP-адресов, предназначенных для атаки. В результате каждый такой адрес производит ненормальное число соединений и запросов, не характерное для реального пользователя. Для справки: Не всегда подобный расклад свидетельствует о проведении DDoS-атаки. Подобные же действия можно наблюдать при использовании forward (анонимного) прокси, потому что его IP-адрес на сервере служит для идентификации любого пользователя, которого он обслуживает. Однако, число заходов и запросов от анонимного прокси будет в разы меньше, чем при атаке.
- Поскольку речь идет о ботах, производящих трафик, «перегревающий» сервер, интенсивность этого трафика гораздо выше, чем способен производить реальный пользователь.
- Заголовок клиентского приложения User-Agent иногда отображается в нестандартной конфигурации.
- Иногда атаку можно распознать по заголовку Referer.
Возможности NGINX и NGINX Plus по борьбы с DDoS-атаками
Многие характеристики NGINX и NGINX Plus могут оказать неоценимую помощь при решении вопросов, как справиться с DDoS-атакой. Работает это по двум направлениям: через управление входящим трафиком и через контроль его распределения по внутренним серверам.
Ограничение частоты запросов
Вы можете отрегулировать частоту входящих запросов через NGINX и NGINX Plus до значения, характерного для реальных пользователей. Например, вы полагаете, что на вашу главную страницу пользователи заходят каждые две секунды. Вы можете настроить оборудование на эту частоту запросов к странице – 30 в минуту.
limit_req_zone $binary_remote_addr zone=one:10m rate=30r/m;
server {
...
location /login.html {
limit_req zone=one;
...
}
}
Директива
limit_req_zone
формирует общую зону памяти one для хранения установленного числа запросов по заданному ключу. В данном случае это клиентский IP-адрес ($binary_remote_addr
). Директива limit_req
в блоке /login.html
отсылает к этой зоне памяти.Ограничение числа соединений
Вы можете наложить ограничения на число соединений, которые могут исходить от одного IP-адреса клиента. Опять же оценив их значение, характерное для реального пользователя. Например, вы можете установить не больше 10 заходов с одного IP в область /store вашего сайта.
limit_conn_zone $binary_remote_addr zone=addr:10m;
server {
...
location /store/ {
limit_conn addr 10;
...
}
}
Как и в предыдущем примере, директива
limit_conn_zone
формирует общую зону памяти add
для хранения запросов по заданному ключу – клиентскому IP-адресу $binary_remote_addr
. limit_conn
в теле /store
отсылает к этой зоне памяти и устанавливает ограничение 10 соединениями с каждого клиентского IP.Закрытие медленных соединений
Вы можете закрыть соединения, которые посылают данные чересчур редко, что может быть признаком того, что их главная цель – быть открытыми на протяжении долгого времени и препятствовать новым соединениям. Этот тип программы для атаки называют Slowloris. Директива
client_body_timeout
контролирует время ожидания NGINX между записями в теле клиента. Директива client_header_timeout
делает то же для заголовков. По умолчанию в обоих случаях ставится 60 секунд. В следующем примере этот интервал устанавливается на значении 5 секунд.server {
client_body_timeout 5s;
client_header_timeout 5s;
...
}
Внесение IP-адресов в «черный список»
Если вы распознали IP, используемые для атаки, вы можете внести их в «черный список» при помощи директивы deny, NGINX и NGINX Plus больше не будут реагировать на запросы с этих адресов. Например, если вы выяснили, что атака идет из области 123.123.123.1 через адрес 123.123.123.16:
location / {
deny 123.123.123.0/28;
...
}
Если таких адресов несколько:
location / {
deny 123.123.123.3;
deny 123.123.123.5;
deny 123.123.123.7;
...
}
Создание разрешенного списка IP-адресов
Допустим, доступ к вашему сайту или приложению открыт для заранее известного диапазона IP-адресов. Вы можете прописать его с помощью директив allow и deny. К примеру, вы можете предоставить доступ лишь адресам локальной сети.
location / {
allow 192.168.1.0/24;
deny all;
...
}
IP-адреса, не отвечающие условиям установленного диапазона, будут заблокированы.
Кэширование для предотвращения скачков трафика
Вы можете настроить NGINX и NGINX Plus, чтобы они поглощали скачки трафика во время атаки через кэширование и пропись его параметров, они будут игнорировать обратные запросы. Это можно сделать следующими вариантами:
Параметр обновления в
proxy_cache_use_stale
сообщает NGINX, что, когда ему необходимо провести обновление устаревших объектов в кэше, ему следует отправлять лишь один запрос и держать открытым доступ к таким объектам для клиентов, пока обновление с внутренних серверов не получено.Key defined by the
proxy_cache_key
обычно состоит из встроенных вариаций (default key
, $scheme$proxy_host$request_uri
имеет три вариации). Если значение включает $query_string
, то атака, посылающая редкие строки запросов, может привести к избыточному кэшированию. Не рекомендуется включать этот вариант в ключ, если в этом нет насущной необходимости.Блокировка запросов
Вы можете настроить NGINX и NGINX Plus для блокировки следующих видов запросов:
- Запросы к определенному URL, которое может быть под угрозой.
- Запросы, где заголовки User-Agent имеют значение, не соответствующее обычному клиентскому трафику.
- Запросы, в которых заголовки Referer могут быть определены, как связанные с атакой.
- Запросы, в которых остальные заголовки кажутся подозрительными.
Например, если вы решили, что атака нацелена на URL /foo.php, можете заблокировать все запросы к странице:
location /foo.php {
deny all;
}
Если вы выяснили, что запросы DDoS-атаки имеют значение foo или bar в заголовках User Agent, можете заблокировать и их:
location / {
if ($http_user_agent ~* foo|bar) {
return 403;
}
...
}
По такому же принципу можно работать с другими заголовками, которые имеют значения, указывающие на угрозу атаки.
Ограничение соединений к внутренним серверам
NGINX и NGINX Plus могут одновременно управляться с большим числом соединений, чем позволяют себе внутренние серверы. С помощью NGINX Plus вы можете ограничить количество соединений к каждому из внутренних серверов. Допустим, вы желаете ограничить число подключений к двум внутренним серверам группы, обслуживающей сайт, числом 200:
upstream website {
server 192.168.100.1:80 max_conns=200;
server 192.168.100.2:80 max_conns=200;
queue 10 timeout=30s;
}
Параметр
max_conns
устанавливает для каждого сервера максимальное число подключений, открытых NGINX Plus. Директива queue
ограничивает число запросов находящихся в очереди, если все серверы группы превысили свой лимит. В этой же строке прописано время нахождение запроса в очереди – 30 секунд.Range-Based-атаки
Есть вариант атаки, при котором заголовок функции Range отправляется с очень большим значением, что может привести к переполнению буфера. Для того чтобы узнать, как с помощью NGINX и NGINX Plus справляться с этим типом атаки советуем почитать эту статью.
Как управляться с большими загрузками
DDoS-атаки обычно ведут к критическому повышению уровня загрузки. Почитать о том, как научить NGINX и NGINX Plus и ОС справляться с этой проблемой, можно здесь.
Обнаружение DDoS-атаки
До сих пор мы обсуждали, как можно использовать NGINX и NGINX Plus, чтобы смягчить последствия DDoS-атаки. Но можно ли с помощью этих серверов обнаружить саму атаку? Модуль NGINX Plus Status предоставляет детальные метрические показатели трафика, который был распределен по внутренним серверам. Этот инструмент позволяет распознать ненормальные состояния трафика. NGINX Plus имеет функцию панели управлении страницей сайта, где отображаются графики текущего состояния работы его системы (пример можно посмотреть здесь: demo.nginx.com/status.html). Те же самые показатели доступны через API, их можно встроить в собственную или стороннюю систему мониторинга, и отслеживать во времени изменения трафика, предупреждая необычные его состояния.
Резюме
NGINX и NGINX Plus могут оказать неоценимую помощь при решении вопросов, как купировать DDoS-атаки. При этом NGINX Plus обладает дополнительными свойствами для защиты от подобного рода атак, предупреждающими их появление.
Комментарии (5)
megareez
14.01.2016 15:48+5Почему не написали про 444 код
что на основе скориговой системы можнло логировать и блогировать через ipset или iptables raw
set $add 1;
location /index.php {
limit_except GET POST {
deny all;
}
set $ban "";
if ($http_referer = "" ) {set $ban $ban$add;}
if ($request_method = POST ) {set $ban $ban$add;}
if ($query_string = «action=login» ){set $ban $ban$add;}
if ($ban = 111 ) {
access_log /var/log/[133]nginx/ban IP;
return 444;
}
proxy_pass 127.0.0.1:8000;
}
ну и метрик для скоринга накрутить
ни слова про тюнинг ядра… хоть это напрямую к нгинксу и не относится тему можно было бы осветить.scarab
14.01.2016 21:06А не поделитесь опытом работы со скоринговыми системами, если таковой имеется?
simpleadmin
14.01.2016 22:48+1if ($http_referer = "" ) {set $ban $ban$add;}
if ($request_method = POST ) {set $ban $ban$add;}
if ($query_string = «action=login» ){set $ban $ban$add;}
if ($ban = 111 ){
return 444;
}
>>
map "$http_referer$request_method$query_string" $ban { "POSTaction=login" "1"; } if ($ban) { return 444; }
alekciy
15.01.2016 10:50+2Директива client_body_timeout контролирует время ожидания NGINX между записями в теле клиента. Директива client_header_timeout делает то же для заголовков. По умолчанию в обоих случаях ставится 60 секунд. В следующем примере этот интервал устанавливается на значении 5 секунд.
Аккуратнее с такими значениями. Можно легко так пустить под нож мобильных клиентов.
UncleAndy
К сожалению, нормальную DDoS атаку таким образом не отразишь. Кроме того, если будет забит сетевой канал, никакие средства nginx не помогут.