Модуль Nginx для борьбы с DDoS (HTTP-флуд)

Автором Nginx модуля testcookie-nginx-module является Эльдар Заитов (Eldar Zaitov), исходный код находится на GitHub.

HTTP Flood (HTTP-флуд) это тип DDoS атаки, в котором атакующий манипулирует GET или POST запросами для атаки на Web-Сервер или приложение. Модуль testcookie работает как быстрый фильтр между ботами и бэкэндом во время L7 DDoS атаки и позволяет отсеивать мусорные запросы.

Модуль testcookie может защитить только от ботов, которые не имеют механизмов HTTP cookie и редиректа. Иногда конечно попадаются более продвинутые — такие могут использовать cookies и обрабатывать редиректы. Чтобы избежать автоматического парсинга, проверяющая кука может быть зашифрована с помощью AES-128 и позже расшифрована на клиентской стороне JavaScript. Модуль проверяет входящего клиента на такие возможности его браузера:

  1. Умеет ли клиент выполнять HTTP Redirect.
  2. Поддерживает ли JavaScript.
  3. Тот ли он браузер, за который себя выдает.

Проверка реализована с помощью кукисов с использованием разных методов:

  • «Set-Cookie» + редирект с помощью 301 HTTP Location;
  • «Set-Cookie» + редирект с помощью HTML meta refresh;
  • произвольным шаблоном, причем можно использовать JavaScript.

Внимание!

Модуль testcookie блокирует доступ для многих легитимных пользователей (фактически всех мобильных устройств), всех ботов в том числе и ботов поисковых систем, таких как Googlebot. Если вы планируете оставить testcookie на постоянной основе, убедитесь, что вы при этом не пропадете из поисковой выдачи! Модуль не работает с консольными браузерами Links, w3m и им подобными; не спасает от ботов, оснащенных полноценным браузерным движком с JavaScript. Другими словами, прежде чем использовать, продумайте все последствия.

Как добавить модуль testcookie на рабочий Nginx

В этой статье рассмотрим два метода установки модуля testcookie:

  1. Компиляция модуля и полная перекомпиляция Веб-сервера Nginx (основной способ). ВАЖНО: во время установки данного модуля, этим способом, ни на секунду Ваши сайты не перестанут работать!
  2. Опишу возможность добавления модуля testcookie без перекомпиляции Nginx.

Все действия для тестировались CentOS Linux 7.9.

Поведем подготовительную работу и установим программы для сборки Nginx:

yum install gcc gcc-c++ kernel-devel
yum groupinstall 'Development Tools'

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

Создадим новый конфиг /etc/nginx/sites-enabled/localhost.conf

server {
    listen 80;
    server_name localhost;
 
    location /nginx_status {
        stub_status on;
        access_log off;
        allow 127.0.0.1;
        deny all;
    }
}

Применяем настройки

systemctl reload nginx

Проверяем:

curl http://localhost/nginx_status

Статистика имеет вид:

Active connections: 6 
server accepts handled requests
 25 25 159 
Reading: 0 Writing: 1 Waiting: 5 

Всё! Статистику мы видим.

Теперь скачем сам модуль testcookie-nginx-module

wget https://github.com/kyprizel/testcookie-nginx-module/archive/refs/heads/master.zip

Содержимое распакуйте в папку по пути:

mkdir /root/testcookie-nginx-module
unzip master.zip -d /root/testcookie-nginx-module/
  1. Узнаем версию nginx
    nginx -v
    nginx version: nginx/1.20.2
  2. Скачайте с сайта nginx.org версию nginx, которая установлена на Вашем сервере. У меня версия nginx 1.20.2 и я скачиваю такую же версию:
    cd
    wget http://nginx.org/download/nginx-1.20.2.tar.gz
  3. Распаковываем:
    tar -xzvf nginx-1.20.2.tar.gz
  4. Заходим в папку
    cd nginx-1.20.2/

На этом шаге на нужно выяснить с какими модулями и параметрами был собран наш Nginx.

  1. Узнаем установленные модули:
    nginx -V
  2. У меня выдало вот такое (весь листинг указывать не буду):
    nginx version: nginx/1.20.2
    built by gcc 4.8.5 20150623 (Red Hat 4.8.5-44) (GCC)
    built with OpenSSL 1.0.2k-fips  26 Jan 2017
    TLS SNI support enabled
    configure arguments: --prefix=/etc/nginx --sbin-path=/usr/sbin/nginx
    ...

    Нас интересует все что после configure arguments. Приводим к виду ниже, заменив configure arguments: на ./configure И сохраняем полученный код в текстовый файл.

    ./configure --prefix=/etc/nginx --sbin-path=/usr/sbin/nginx --modules-path=/usr/lib64/nginx/modules --conf-path=/etc/nginx/nginx.conf --error-log-path=/var/log/nginx/error.log --http-log-path=/var/log/nginx/access.log --pid-path=/var/run/nginx.pid --lock-path=/var/run/nginx.lock --http-client-body-temp-path=/var/cache/nginx/client_temp --http-proxy-temp-path=/var/cache/nginx/proxy_temp --http-fastcgi-temp-path=/var/cache/nginx/fastcgi_temp --http-uwsgi-temp-path=/var/cache/nginx/uwsgi_temp --http-scgi-temp-path=/var/cache/nginx/scgi_temp --user=nginx --group=nginx --with-compat --with-file-aio --with-threads --with-http_addition_module --with-http_auth_request_module --with-http_dav_module --with-http_flv_module --with-http_gunzip_module --with-http_gzip_static_module --with-http_mp4_module --with-http_random_index_module --with-http_realip_module --with-http_secure_link_module --with-http_slice_module --with-http_ssl_module --with-http_stub_status_module --with-http_sub_module --with-http_v2_module --with-mail --with-mail_ssl_module --with-stream --with-stream_realip_module --with-stream_ssl_module --with-stream_ssl_preread_module --with-cc-opt='-O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector-strong --param=ssp-buffer-size=4 -grecord-gcc-switches -m64 -mtune=generic -fPIC' --with-ld-opt='-Wl,-z,relro -Wl,-z,now -pie'

В Шаг 4, мы сохранили в файл ключи компиляции. Добавим к ним информацию о расположении исходников модуля testcookie:

--add-module=/root/testcookie-nginx-module/testcookie-nginx-module-master

У меня получилось вот так (это полный листинг). Помним что мы находимся в директории nginx-1.20.2. Запускаем полученную команду

./configure --prefix=/etc/nginx --sbin-path=/usr/sbin/nginx --modules-path=/usr/lib64/nginx/modules --conf-path=/etc/nginx/nginx.conf --error-log-path=/var/log/nginx/error.log --http-log-path=/var/log/nginx/access.log --pid-path=/var/run/nginx.pid --lock-path=/var/run/nginx.lock --http-client-body-temp-path=/var/cache/nginx/client_temp --http-proxy-temp-path=/var/cache/nginx/proxy_temp --http-fastcgi-temp-path=/var/cache/nginx/fastcgi_temp --http-uwsgi-temp-path=/var/cache/nginx/uwsgi_temp --http-scgi-temp-path=/var/cache/nginx/scgi_temp --user=nginx --group=nginx --with-compat --with-file-aio --with-threads --with-http_addition_module --with-http_auth_request_module --with-http_dav_module --with-http_flv_module --with-http_gunzip_module --with-http_gzip_static_module --with-http_mp4_module --with-http_random_index_module --with-http_realip_module --with-http_secure_link_module --with-http_slice_module --with-http_ssl_module --with-http_stub_status_module --with-http_sub_module --with-http_v2_module --with-mail --with-mail_ssl_module --with-stream --with-stream_realip_module --with-stream_ssl_module --with-stream_ssl_preread_module --with-cc-opt='-O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector-strong --param=ssp-buffer-size=4 -grecord-gcc-switches -m64 -mtune=generic -fPIC' --with-ld-opt='-Wl,-z,relro -Wl,-z,now -pie' --add-module=/root/testcookie-nginx-module/testcookie-nginx-module-master

На выходе не должно быть ошибок. Теперь компилируем, используя утилиту make:

make

После:

make install

Всё. Перезагрузите nginx:

systemctl restart nginx

Введите команду:

nginx -V

Вы увидите, что теперь ваш Nginx имеет Anti-DDoS модуль, который можете настраивать.

Этот вариант, я нашел в просторах интернета. Я не понимаю его глубинного смысла, но возможно для каких-то задач он пригодится.

  1. Все делаем как в Шаг 5.1, но заканчиваем на этапе make, make install уже НЕ делаем.
  2. Копируем собранные бинарный файл (objs/ngx_http_testcookie_access_module.so) модуля в /etc/nginx/modules
  3. И подгружаем модуль строкой в nginx.conf в самом верху:
    load_module "modules/ngx_http_testcookie_access_module.so";
  4. Теперь перегружаем Nginx
    systemctl restart nginx

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

  • Вы собрали не ту версию
    Restarting nginx: nginxnginx: [emerg] module "/etc/nginx/modules/ngx_http_testcookie_access_module.so" version 1009011 instead of 1009012 in /etc/nginx/nginx.conf:8
  • Вы собрали не с теми параметрами
    Restarting nginx: nginxnginx: [emerg] module "/etc/nginx/modules/ngx_http_testcookie_access_module.so" is not binary compatible in /etc/nginx/nginx.conf:8

Пробуйте, изучайте, но если спешите, то использует проверенный способ с полной перекомпиляцией и модуля и Nginx.

Пример использования testcookie

Добавляем в конфигурацию вашего сервера (файл nginx.conf в раздел http) параметры по примеру ниже.

http {
#default config, module disabled
testcookie off;
#setting cookie name
testcookie_name BPC;
#setting secret
testcookie_secret 0cc76cab5b6fbeb3f9f307247d90f406;
#setting session key
testcookie_session $remote_addr;
#setting argument name
testcookie_arg ckattempt;
testcookie_max_attempts 3;
#setting p3p policy
testcookie_p3p 'CP="CUR ADM OUR NOR STA NID", policyref="/w3c/p3p.xml"';
#setting fallback url
testcookie_fallback http://google.com/cookies.html?backurl=http://$host$request_uri;
#configuring whitelist
testcookie_whitelist {
8.8.8.8/32;
}
#setting redirect via html code
testcookie_redirect_via_refresh on;
#enable encryption
testcookie_refresh_encrypt_cookie on;
#setting encryption key
testcookie_refresh_encrypt_cookie_key deadbeefdeadbeefdeadbeefdeadbeef;
#setting encryption iv
testcookie_refresh_encrypt_cookie_iv deadbeefdeadbeefdeadbeefdeadbeef;
#setting response template
testcookie_refresh_template '<html><body><script>document.cookie="BPC=$testcookie_set";document.location.href="$testcookie_nexturl";</script></body></html>';

Опишу некоторые параметры, более подробно смотрите в документации к модулю.

  • Параметры testcookie_secret, testcookie_refresh_encrypt_cookie_key и testcookie_refresh_encrypt_cookie_iv заполняем случайно с генерируемым числами длиной 32 символа, например такой консольной командой
     head -c16 </dev/urandom | xxd -p
    6554c67d12b2100d82af29decd833219
  • testcookie_refresh_template - логика чтобы мы будем делать с поступившим запросом. В моем примере происходит проверка на возможность установит куки, если успешно пользователю открывается сайт как обычно.

Чтобы чтобы начать использовать testcookie, вы должны его включить для определённого сайта. Для этого достаточно добавить строку testcookie on;

location / {
        testcookie on;
        ...

Проверяем работу. Для этого нужно сделать запрос к сайту браузером которые не поддерживает cookie. Вполне подойдет cURL тестирование HTTP заголовков, SOCKS и другие.

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

curl https://dieg.info
<html><body>
<script>document.cookie="BPC=7c4fae01484246f74899b29583854c7b";
document.location.href="https://dieg.info/?ckattempt=1";</script></body></html>

Больше вариантов для генерации из консоли смотрите https://bestvpn.report/answers/how-to-get-a-random-string-of-32-hexadecimal-digits-through-command-line/

Заключение

Поздравляю, Вы успешно настроили модуль Анти-DDoS в Nginx. Для автоматизации включения/выключение testcookie системные администраторы используют скрипты, но я не стал здесь его описывать. На мой взгляд, использования этого модуля на постоянной основе не разумно в 90% случаях из 100%.

PQ VPS сервера в 28+ странах.