Глава 7. Управления безопасностью

Введение

Мероприятия по безопасности выполняются на различных уровнях и для её истинной прочности следует иметь множество уровней в вашей модели безопасности. В данной главе мы пройдём множество различных способов по осуществлению мероприятий безопасности для ваших веб приложений при помощи NGINX и NGINX Plus. Вы можете применять в сочетании друг с другом многие из этих методов для содействия упрочению безопасности. Далее приводится целый ряд разделов по безопасности, которые рассматривают свойства NGINX и NGINX Plus, способные содействовать упрочнению вашего приложения. Вам следует обратить внимание на то, что эта глава не касается одной из самых крупных функциональностей безопасности NGINX, модуля NGINX ModSecurity 3.0, который превращает NGINX в Веб приложение межсетевого экрана (WAF, Web Application Firewall). Для изучения дополнительных возможностей WAF выгрузите ModSecurity 3.0 and NGINX: Quick Start Guide

Основанный на IP доступ

Задача

Вам требуется контролировать доступ клиента на основе значения IP адреса самого клиента.

Решение

Воспользуйтесь методом доступа HTTP для управления доступом к защищаемым ресурсам:


location /admin/ {
    deny 10.0.0.1;
    allow 10.0.0.0/20;
    allow 2001:0db8::/32;
    deny all;
}
 	   

Данный конкретный блок location разрешает доступ со всех адресов IPv4 в 10.0.0.0/20 за исключением 10.0.0.1, допускает доступ с адресов IPv6 из подсети 2001:0db8::/32 и возвращает 403 для всех поступающих с прочих адресов запросов. Такие директивы allow и deny допустимы в контекстах HTTP, server и location. Правила проверяются последовательно пока не будет найдено соответствие для удалённого адреса запрашивающей стороны.

Обсуждение

Защита значимых ресурсов и служб в Интернете должна выполняться на разных уровнях. NGINX предоставляет такую возможность быть одним из подобных уровней. его директива deny блокирует доступ к некому заданному контексту, в то время как директива allow может применяться для допуска подмножеств в имеющемся заблокированном доступе. Вы можете применять IP адреса, причём IPv4 и IPv6, диапазоны блоков CIDR, ключевое слово all, а также сокет Unix. Обычно при защите некого ресурса следует разрешат некий блок внутренних IP адресов и запрещать доступ для all.

Разрешение обмена ресурсами между источниками

Задача

Вы обслуживаете ресурсы из одного домена и вам требуется разрешить совместное использование ресурсов между источниками (CORS, Cross-Origin Resource Sharing) чтобы позволить браузерам применять эти ресурсы.

Решение

Для включения CORS измените заголовки на основе метода request:


map $request_method $cors_method {
  OPTIONS 11;
  GET 1;
  POST 1;
  default 0;
}
server {
  ...
  location / {
    if ($cors_method ~ '1') {
            add_header 'Access-Control-Allow-Methods'
                'GET,POST,OPTIONS';
            add_header 'Access-Control-Allow-Origin'
                '*.example.com';
            add_header 'Access-Control-Allow-Headers'
                       'DNT,
                       Keep-Alive,
                       User-Agent,
                       X-Requested-With,
                       If-Modified-Since,
                       Cache-Control,
                       Content-Type';
    }
    if ($cors_method = '11') {
        add_header 'Access-Control-Max-Age' 1728000;
        add_header 'Content-Type' 'text/plain; charset=UTF-8';
        add_header 'Content-Length' 0;
        return 204;
    }
  }
}
 	   

В данном методе происходит много чего, что было сокращено при помощи некого map группе приводимых методов GET и POST всем сразу. Приводимый метод запроса OPTIONS возвращает некий предполётный запрос для запрашивающего клиента относительно этих правил CORS. Под CORS разрешены методы OPTIONS, GET и POST. Установка значения заголовка Access-Control-Allow-Origin делает возможным обслуживание содержимого с данного сервера, также применимым для страниц, происходящих с тех ,которые соответствуют данному заголовку. Такой предполётный запрос может быть кэширован для данного клиента на протяжении 1 728 000 секунд, или 20 дней.

Обсуждение

Подобные JavaScript ресурсы применяют CORS когда запрашиваемые ими ресурсы расположены в отличающихся от из собственных доменах. Когда некий запрос рассматривается как предполагающий совместное применение источников, его браузеру требуется следовать правилам CORS. Браузер запрашивающей стороны не будет применять такой ресурс если у него нет заголовков, которые именно это ему предписывают делать. Для того чтобы разрешить использование наших ресурсов с прочих поддоменов, нам требуется установить необходимые заголовки CORS, что может быть выполнено при помощи директивы add_header Если таким запросом являетс некий GET, HEAD или POST со стандартным типом содержимого, и такой запрос не имеет особых заголовков, его браузер сделает соответствующий запрос и проверит только его происхождение. Прочие методы заставят этот браузер выполнять необходимый предполётный запрос для проверки условий того сервера, которому подчинён такой ресурс. Если у вас не установлен надлежащий заголовок, браузер запроса получит некое сообщение об ошибке когда попытается воспользоваться данным ресурсом.

Шифрование стороны клиента

Задача

Вам требуется шифровать обмен между своим сервером NGINX и его клиентом.

Решение

Для шифрования обмена воспользуйтесь одним из имеющихся модулей SSL, например, ngx_http_ssl_module или ngx_stream_ssl_module:


http { # All directives used below are also valid in stream
    server {
        listen 8433 ssl;
        ssl_protocols TLSv1.2 TLSv1.3;
        ssl_ciphers HIGH:!aNULL:!MD5;
        ssl_certificate /etc/nginx/ssl/example.pem;
        ssl_certificate_key /etc/nginx/ssl/example.key;
        ssl_certificate /etc/nginx/ssl/example.ecdsa.crt;
        ssl_certificate_key /etc/nginx/ssl/example.ecdsa.key;
        ssl_session_cache shared:SSL:10m;
        ssl_session_timeout 10m;
    }
}
 	   

Данная конфигурация настраивает сервер на ожидание по порту с шифрованием SSL, 8443. Данный сервер принимает протоколы SSL версий TLSv1.2 и TLSv1.3. Для применения данным сервером раскрываются два набора местоположений сертификата и пар ключей. Данному серверу предписывается применять наивысшую предлагаемую его клиентом неприступность при ограничении небольшим числом не являющихся безопасными. Поскольку мы предоставили некую пару ключей ECC (Elliptic Curve Cryptopgraphy), наивысшим приоритетом обладает именно шифрование ECC. Имеющиеся кэш SSL сеанса и таймаут делают для исполнителей возможным кэшировать и сохранять параметры сеанса на заданный промежуток времени. Существует большое число прочих параметров кэширования сеанса, которые способствуют производительности и безопасности для любых видо вариантов применения. Вы можете использовать параметры кэширования сеанса совместно друг с другом. Однако если определять параметр без значения по умолчанию отключит то значение по умолчанию, которое встроено в кэширование сеанса.

Обсуждение

Безопасный транспортный уровень является наиболее распространённым способом шифрования информации при передаче. На момент написания данной книги протокол TLS более предпочтителен нежели протокол SSL. Это обусловлено тем, что версии SSL с 1 по 3 теперь рассматриваются как лишённые защищённости. Хотя само название протокола и может быть иным, TLS всё- таки устанавливает secure socket layer (протокол защищённых сокетов). NGINX позволяет вашей службе защищать информацию между вами и вашими клиентами, что в свою очередь защищает и самого клиента и ваш бизнес. При применении подписанного сертификата вам требуется прицеплять свой сертификат к имеющейся цепочке, причём ваш сертификат должен пребывать в надлежащем файле над этой цепочкой. Если ваш центр сертификации предоставил множество файлов в вашей цепочке, он также может предоставить и порядок их следования. Кэширование SSL сеанса расширяет производительность через отсутствие потребности согласования версий SSL/ TLS и шифра.

При тестировании было установлено, что сертификаты ECC быстрее сертификатов RSA с той же строгостью. Его размер ключа меньше, что в результате приводит к возможности обслуживания большего числа подключений SSL/ TLS, причём с более быстрым квитированием. NGINX позволяет настраивать несколько сертификатов и ключей, а затем обслуживать оптимальный для браузера клиента сертификат. Это делает для вас возможным использовать преимущества новой технологии, но при этом обслуживать и старых клиентов.

Также ознакомьтесь

Mozilla Server Side TLS Page

Mozilla SSL Configuration Generator

Test Your SSL Configuration with SSL Labs SSL Test

Восходящее шифрование

Задача

Вам требуется шифровать обмен между NGINX и конкретной службой восходящего потока, а также устанавливать особые правила согласования для регулировок надёжности или когда данный восходящий поток пребывает вне вашей безопасной сетевой среды.

Решение

Для задания правил SSL вам следует применить директивы SSL для своего модуля посредника HTTP:


location / {
    proxy_pass https://upstream.example.com;
    proxy_ssl_verify on;
    proxy_ssl_verify_depth 2;
    proxy_ssl_protocols TLSv1.2;
}
 	   

Эти директивы посредника устанавливают особые правила SSL чтобы подчиняться NGINX. Эти настраиваемые директивы гарантируют что NGINX удостоверяет что данный сертификат и цепочка в данной службе восходящего потока подтверждён до двух сертификатов в глубину. Соответствующая директива proxy_ssl_protocols определяет что этот NGINX будет применять только TLS с версией 1.2. По умолчанию NGINX не проверяет сертификаты восходящего потока и применяет все версии TLS.

Обсуждение

Имеющиеся директивы для нашего модуля посредника HTTP очень многочисленны, а если вам требуется шифровать обмен восходящего потока, вам следует по крайней мере включить установление подлинности. Вы можете выступать посредником поверх HTTPS изменяя протокол в том значении, которое передаётся в соответствующую директиву proxy_pass. Тем не менее, это не подтверждает имеющийся сертификат восходящего потока. Прочие директивы, такие как proxy_ssl_certificate и proxy_ssl_certificate_key, позволяют вам ограничивать шифрование восходящего потока расширенной безопасностью. Вы также можете предписать proxy_ssl_crl или некий список аннулированных сертификатов, который перечисляет сертификаты, которые более не рассматриваются как допустимые. Такие директивы посредника SSL помогают упрочнять каналы взаимодействия вашей системы внутри вашей собственной сетевой среды или поверх общедоступного интернета.

Безопасность местоположения

Задача

Вам требуется при помощи ключа безопасности защитить некий блок location.

Решение

secure_link_secret:


location /resources {
    secure_link_secret mySecret;
    if ($secure_link = "") { return 403; }

    rewrite ^ /secured/$secure_link;
}

location /secured/ {
    internal;
    root /var/www;
}
 	   

Данная конфигурация создаёт некий внутренний и повёрнутый в общедоступную стороны блоки location. Развёрнутый в сторону общей доступности блок location /resources будет возвращать 403 Forbidden всякий раз когда URI его запроса содержит некую строку хэширования md5, которая не может быть проверена тем кодом безопасности, который предоставляется в установленной директиве secure_link_secret. Значение переменной $secure_link является некой пустой строкой пока значение хэша URI не удостоверено.

Обсуждение

Предоставление безопасности при помощи кода безопасности является великолепным способом гарантии того что ваши файлы защищены. Такой код безопасности применяется в сочетании со значением URI. Данная строка далее хэшируется посредством md5, и в получаемом URI применяются шестнадцатеричные цифры данного хэша md5. Этот хэш помещается в надлежащую ссылку и вычисляется NGINX. NGINX обладает информацией относительно значений запрашиваемых пути и файла, поскольку они пребывают в URI после значения хэша. NGINX также знает ваш код безопасности (secret), поскольку он предоставляется через соответствующую директиву secure_link_secret. NGINX имеет возможность быстро удостоверивать значение хэша md5 и сохранять получаемый URI в значении переменной $secure_link. Если же значение хэша не подтверждается, значение переменной устанавливается в некую пустую строку. Важно отметить, что те аргументы, которые передаются в secure_link_secret обязаны быть статической строкой; они не могут быть некой переменной.

Генерация безопасного соединения при помощи ключа безопасности

Задача

Вам требуется сгенерировать в своём приложении некую безопасную ссылку при помощи какого- то кода безопасности.

Решение

Имеющийся в NGINX модуль безопасной ссылки принимает значения шестнадцатеричных цифр некой хэшированной md5 строки, причём такая строка представляет собой сцепление значение URI пути и сам код безопасности (secret). Отталкиваясь от своего последнего рецепта, Безопасность местоположения, мы создадим защищённую ссылку, которая будет работать с предыдущим примером конфигурации с учётом того что имеется некий файл, представленный в /var/www/secured/index.html. Для выработки требуемых значений шестнадцатеричных цифр md5 мы можем применить команду Unix openssl:


$ echo -n 'index.htmlmySecret' | openssl md5 -hex
(stdin)= a53bee08a4bf0bbea978ddf736363a12
		

Здесь мы показываем значение защищаемого нами URI, index.html, сцепляемого с нашим кодом безопасности, mySecret. Эта строка передаётся в соответствующую команду openssl для вывода шестнадцатеричных цифр md5.

Ниже приводится некий пример построения в Python тех же самых шестнадцатеричных цифр с применением библиотеки hashlib, которая входит в состав Стандартной библиотеки Python:


import hashlib
hashlib.md5.(b'index.htmlmySecret').hexdigest()
'a53bee08a4bf0bbea978ddf736363a12'
 	   

Теперь, когда у нас имеются данные шестнадцатеричные цифры, мы можем применять их в неком URL. Нашим примером будет www.example.com, выполняющий некий запрос для своего файла /var/www/secured/index.html через location /resources. Нашим полным URL будет следующее:


www.example.com/resources/a53bee08a4bf0bbea978ddf736363a12/\
index.html
 	   

Обсуждение

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

Безопасность местоположения при помощи ограниченной даты

Задача

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

Решение

Для настройки срока истечения действия воспользуйтесь прочими включёнными в обсуждаемый модуль безопасных ссылок директивами и применяйте переменные в своей защищённой ссылке:


location /resources {
    root /var/www;
    secure_link $arg_md5,$arg_expires;
    secure_link_md5 "$secure_link_expires$uri$remote_addr mySecret";
    if ($secure_link = "") { return 403; }
    if ($secure_link = "0") { return 410; }
}
 	   

Приводимая директива secure_link получает два разделяемые запятой параметра. Значением первого параметра является переменная, которая содержит значение хэша md5. Данный пример использует некий аргумент HTTP md5. Вторым параметром является переменная, которая содержит значение времени истечения срока данной ссылки, исчисляемого в формате времени эпохи Unix. Следующая директива secure_link_md5 получает некий отдельный параметр, объявляющий значение формата той строки, которая применяется для построения значения хэша md5. Как и для прочих конфигураций, когда это значение хэша не проходит процедуру удостоверения, значение переменной $secure_link устанавливается в некую пустую строку. Тем не менее, при данном применении, в случае соответствия значения хэша, но при истечении срока действия значение переменной $secure_link будет установлено в 0.

Обсуждение

Данное применение защищённой ссылки является более гибким и выглядит более понятным чем тот secure_link_secret, который показан в рецепте Безопасность местоположения. При помощи этих директив мы способны применять любое число доступных для NGINX переменных, в своей хэшируемой строке. Использование специфичных для пользователя переменных в такой строке хэша усилит вашу безопасность, поскольку у пользователей не будет возможности выставлять на продажу ссылки к защищённым ресурсам. Рекомендуется применять переменные, подобные $remote_addr или $http_x_forwarded_for, либо некий заголовок куки сеанса, вырабатываемый вашим приложением. Значения аргументов для secure_link может поступать из любых предпочитаемых вами переменных, и они могут именоваться так чтобы лучше соответствовать вашим потребностям. Значения условий относительно значения переменной $secure_link устанавливаются для возврата известных кодов HTTP для Forbidden и Gone. Значение 410 HTTP, Gone прекрасно подходит для просроченных ссылок, так как данное условие рассматривается как неизменное.

Генерация ссылки с ограниченным сроком

Задача

Вам требуется выработать ссылку со сроком истечения.

Решение

Сгенерируйте некий временной штамп (timestamp) для значения срока истечения в формате эпохи Unix. В некой системе Unix вы можете выполнить проверку применив значение даты, мкак это демонстрируется следующим примером:


$ date -d "2020-12-31 00:00" +%s --utc
1609372800
		

Далее вам требуется сцепить строку своего хэша для установления значения строки, настраиваемой при помощи директивы secure_link_md5. В данном случае нашей используемой строкой будет 1293771600/resources/index.html127.0.0.1 mySecret. Значение хэша md5 слегка отличается от просто шестнадцатеричных цифр. Это некий хэш md5 в двоичном формате, кодированный base64, причём символы плюса (+) транслируются в дефисы (-), слэши (/) транслируются в подчёркивания (_), а символы равенства (=) удаляются. Вот некий пример в какой-то системе Unix:


$ echo -n '1609372800/resources/index.html127.0.0.1 mySecret' \
  | openssl md5 -binary \
  | openssl base64 \
  | tr +/ -_ \
  | tr -d =
TG6ck3OpAttQ1d7jW3JOcw
		

Теперь, когда мы имеем свой хэш, мы можем воспользоваться им в качестве некого аргумента совместно с датой истечения срока:


'/resources/index.html?md5=TG6ck3OpAttQ1d7jW3JOcw&expires=1609372800'
 	   

Далее приводится более практичный пример на Python, применяющий относительное время для срока истечения, устанавливающий значение срока истечения ссылки на один час с момента его выработки. На момент написания данной книги этот пример работал с Python 2.7 b 3.x с использванием их Стандартной библиотеки Python:


from datetime import datetime, timedelta
from base64 import b64encode
import hashlib

# Set environment vars
resource = b'/resources/index.html'
remote_addr = b'127.0.0.1'
host = b'www.example.com'
mysecret = b'mySecret'

# Generate expire timestamp
now = datetime.utcnow()
expire_dt = now + timedelta(hours=1)
expire_epoch = str.encode(expire_dt.strftime('%s'))

# md5 hash the string
uncoded = expire_epoch + resource + remote_addr + mysecret
md5hashed = hashlib.md5(uncoded).digest()

# Base64 encode and transform the string
b64 = b64encode(md5hashed)
unpadded_b64url = b64.replace(b'+', b'-')\
    .replace(b'/', b'_')\
    .replace(b'=', b'')

# Format and generate the link
linkformat = "{}{}?md5={}?expires={}"
securelink = linkformat.format(
    host.decode(),
    resource.decode(),
    unpadded_b64url.decode(),
    expire_epoch.decode()
)
print(securelink)
 	   

Обсуждение

При наличии данного шаблона мы имеем возможность вырабатывать некую защищённую ссылку в особом формате, которая может применяться в URI. Данный код безопасности (secret) предоставляет защиту при помощи использования переменных, которые никогда не отправляются определённому клиенту. У вас есть возможность применять столько переменных, сколько вам потребуется чтобы сделать свое местоположение безопасным. Хэширование md5 и кодирование base64 являются распространёнными, оюладают малым весом и доступны почти во всех языках программирования.

Перенаправление HTTPS

Задача

Вам требуется перенаправлять не зашифрованные запросы в HTTPS.

Решение

Воспользуйтесь повторной записью для отправки всего обмена HTTP в HTTPS:


server {
    listen 80 default_server;
    listen [::]:80 default_server;
    server_name _;
    return 301 https://$host$request_uri;
}
 	   

данная конфигурация выполняет ожидание по порту 80 в качестве её сервера по умолчанию как для IPv4, так и для IPv6, а также для любых названий хостов. Оператор return возвращает некий код 301, постоянно выполняя перенаправление в имеющийся в том же самом хосте сервер HTTP и подставляя URI запроса.

Обсуждение

Важно всегда выполнять перенаправление в HTTPS, когда он доступен. Вы можете обнаружить что вам не требуется перенаправлять все запросы, а только те, которые содержат чувствительную информацию, подлежащую передачу между клиентом и сервером. В данном случае вы можете пожелать поместить в оператор return только конкретные расположения, например, /login.

Перенаправление на HTTPS когда SSL/ TLS прекращается до NGINX

Задача

Вам требуется выполнять перенаправление в HTTPS, однако у вас истёк срок SSL/ TLS на уровне перед NGINX.

Решение

Для выяснения того что вам требуется выполнить перенаправление воспользуйтесь стандартным заголовком X-Forwarded-Proto:


server {
    listen 80 default_server;
    listen [::]:80 default_server;
    server_name _;
    if ($http_x_forwarded_proto = 'http') {
        return 301 https://$host$request_uri;
    }
}
 	   

Эта конфигурация во многом схожа с перенаправлением HTTPS. Тем не менее, в данной конфигурации мы выполняем перенаправление только когда значение заголовка X-Forwarded-Proto эквивалентно HTTP.

Обсуждение

Достаточно распространённым случаем является когда у вас может завершится срок действия SSL/ TLS на неком уровне перед NGINX. Одной из причин может быть то что вы делаете нечто подобное сбережению затрат на вычисления. Тем не менее, вам требуется быть уверенным что все запросы являются HTTPS, но при этом сам уровень с прекращённым SSL/ TLS не имеет возможности перенаправления. Он способен, однако, устанавливать заголовки посредника. Эта конфигурация работает с такими уровнями как Amazon Web Services Elastic Load Balancer, который выполняет разгрузку SSL/ TLS без дополнительных затрат. Это удобный трюк для обеспечения защиты для вашего обмена HTTP.

Строгая безопасность доставки HTTP

Задача

Вам требуется проинформировать браузеры что им никогда не следует отправлять запросы поверх HTTP.

Решение

Воспользуйтесь расширением HSTS (HTTP Strict Transport Security) устанавливая заголовок Strict-Transport-Security:


add_header Strict-Transport-Security max-age=31536000;
 	   

Данная конфигурация устанавливает значение заголовка Strict-Transport-Security на максимальный возраст в один год. Он будет инструктировать соответствующий браузер всегда осуществлять некое внутреннее перенаправление при попытке выполнения к данному домену запросов HTTP, чтобы все запросы выполнялись поверх HTTPS.

Обсуждение

Для некоторых приложений один перехваченный атакой с человеком в середине запрос HTTP может стать концом всей компании. Если сообщение некой содержащей чувствительную информацию формы отправляется по HTTP, перенаправление HTTPS из NGINX не спасёт вас; взлом уже произошёл. Данный вариант улучшения безопасности информирует браузер запросов никогда не делать никаких запросов HTTP, а следовательно они никогда не отправляются в незащищённом виде.

Также ознакомьтесь

RFC-6797 HTTP Strict Transport Security

OWASP HSTS Cheat Sheet

Удовлетворение любого числа методов безопасности

Задача

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

Решение

Для указания того что вы желаете удовлетворять неким или даже всем применяемым методам безопасности, для выдачи NGINX инструкции об этом примените директиву satisfy:


location / {
    satisfy any;

    allow 192.168.1.0/24;
    deny all;

    auth_basic           "closed site";
    auth_basic_user_file conf/htpasswd;
}
 	   

Данная конфигурация сообщает NGINX что запрашивающий location / пользователь должен удовлетворять одному из установленных методов безопасности: либо эти запросы должны происходить с блока CIDR 192.168.1.0/24, либо быть способными поддерживать некие имя пользователя и пароль, которые могут быть найдены в обозначенном файле conf/htpasswd. Данная директива satisfy имеет всего два варианта: any или all.

Обсуждение

Описанная директива satisfy является великолепным способом предложения множества способов аутентификации для вашего веб приложения. Определяя any для директивы satisfy, данный пользователь обязан соответствовать одной из предоставленных защит. Определяя в директиве satisfy значение all, запрашивающий пользователь должен соответствовать всем выставленным требованиям безопасности. Данная директива может применяться совместно с http_access_module, описанном в рецепте Основанный на IP доступ, http_auth_basic_module, детализированном в рецепте Базовая аутентификация HTTP, http_auth_request_module, описанном в рецепте Подзапросы аутентификации и описанном в рецепте JWT подтверждение http_auth_jwt_module. Обсуждаемая директива satisfy поможет вам достигать этого для местоположений и серверов, которые требуют глубоких правил защиты.

Динамичное ослабление DDoS

Задача

Вам необходимо некое динамичное решение смягчения DDoS (Distributed Denial of Service).

Решение

Для построения некого осведомлённого о кластере ограничения частот запросов и автоматического чёрного списка воспользуйтесь NGINX Plus:


limit_req_zone   $remote_addr zone=per_ip:1M rate=100r/s sync;
                 # Cluster-aware rate limit
limit_req_status 429;

keyval_zone zone=sinbin:1M timeout=600 sync;
              # Cluster-aware "sin bin" with
              # 10-minute TTL
keyval $remote_addr $in_sinbin zone=sinbin;
              # Populate $in_sinbin with
              # matched client IP addresses

server {
    listen 80;
    location / {
        if ($in_sinbin) {
            set $limit_rate 50; # Restrict bandwidth of bad clients
        }

        limit_req zone=per_ip;
              # Apply the rate limit here
        error_page 429 = @send_to_sinbin;
              # Excessive clients are moved to
              # this location
        proxy_pass http://my_backend;
    }

    location @send_to_sinbin {
        rewrite ^ /api/3/http/keyvals/sinbin break;
              # Set the URI of the
              # "sin bin" key-val
        proxy_method POST;
        proxy_set_body '{"$remote_addr":"1"}';
        proxy_pass http://127.0.0.1:80;
    }

    location /api/ {
        api write=on;
        # directives to control access to the API
    }
}
 	   

Обсуждение

Это решение использует некий синхронизируемый предел частот обращений и синхронизируемое хранилище ключ- значение для динамических откликов на DDoS атаки и смягчения их действия. Параметр sync предоставляет директивам limit_req_zone и keyval_zone синхронные зоны разделяемой с прочими машинами памяти в имеющемся активный- активный кластере NGINX Plus. Данный пример выявляет клиентов, которые отправляют более 100 запросов в секунду вне зависимости от того какой из узлов NGINX Plus получает такой запрос. После того как некий клиент превышает установленный предел частот, его IP адрес добавляется в некое хранилище ключ- значение "sin bin" (Скамейка штрафников) через выполнение запроса API NGINX Plus. Эта Скамейка штрафников синхронизируется по всему кластеру. Последующие запросы от попадающих на Скамейку штрафников клиентов являются предметом очень низкого ограничения полосы пропускания, причём вне зависимости от того какой из узлов NGINX Plus получает их. Ограничение полосы пропускания более предпочтительно чем полное отклонение запросов, ибо оно не становится очевидным сигналом для такого клиента что смягчение DDoS атаки вступило в действие. После 10 минут данный клиент автоматически удаляется со Скамейки штрафников.