Продвинутая защита Nginx

Продвинутая защита Nginx


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

Логирование в формате JSON

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

Вот простой пример из nginx.conf:

 log_format json-logger escape=json '{
   "type": "access-log",
   "time": "$time_iso8601",
   "remote-ip": "$remote_addr",
   "x-forward-for": "$proxy_add_x_forwarded_for",
   "request-id": "$request_id",
   "request-length": "$request_length",
   "response-bytes": "$bytes_sent",
   "response-body-size": "$body_bytes_sent",
   "status": "$status",
   "vhost": "$host",
   "protocol": "$server_protocol",
   "path": "$uri",
   "query": "$args",
   "duration": "$request_time",
   "backend-duration": "$upstream_response_time",
   "backend-status": "$upstream_status",
   "method": "$request_method",
   "referer": "$http_referer",
   "user-agent": "$http_user_agent",
   "active-connections": "$connections_active"
  }';


 access_log /var/log/nginx/access.log json-logger;

Это приведёт к следующему выводу в файле access.log:

{
   "type": "access-log",
   "time": "2025-02-25T16:02:54+00:00",
   "remote-ip": "130.61.78.239",
   "x-forward-for": "130.61.78.239",
   "request-id": "38750f2a1a51b196fa0a76025b0d1be9",
   "request-length": "258",
   "response-bytes": "353",
   "response-body-size": "167",
   "status": "404",
   "vhost": "3.69.78.187",
   "protocol": "HTTP/1.1",
   "path": "/lib/phpunit/Util/PHP/eval-stdin.php",
   "query": "",
   "duration": "0.016",
   "backend-duration": "0.016",
   "backend-status": "404",
   "method": "GET",
   "referer": "",
   "user-agent": "Custom-AsyncHttpClient",
   "active-connections": "1"
  }

Параметризация запросов

Большие размеры тела запроса, длительные тайм-ауты и чрезмерно увеличенные настройки KeepAlive могут серьёзно повлиять на производительность. Чтобы повысить эффективность, лучше устанавливать эти параметры на минимально возможные значения — при этом, конечно, соблюдая требования вашего приложения.

Пример из nginx.conf:

 client_max_body_size 10M;
 client_body_timeout 10s;
 client_header_timeout 10s;
 keepalive_timeout 5s 5s;

Описание параметров:

  • client_max_body_size

Определяет максимальный размер тела HTTP-запроса, который клиент может отправить. Если этот лимит превышен, Nginx возвращает ошибку 413 Request Entity Too Large.

  • client_body_timeout

Задает максимальное время ожидания полного тела запроса. Если за это время тело не получено, соединение закрывается.

  • client_header_timeout

Устанавливает максимальное время ожидания полного заголовка HTTP-запроса от клиента. Если лимит превышен — соединение также закрывается.

  • keepalive_timeout

Определяет, как долго будет оставаться открытым соединение Keep-Alive после последнего запроса.

Первый параметр (например, 5s) задаёт тайм-аут на стороне сервера. Второй (опциональный) параметр передаётся клиенту как предложение о том, как долго он может держать соединение открытым.

Ограничение количества запросов

Если клиент пытается перегрузить веб-сервер частыми запросами, Nginx предоставляет возможность настроить "зоны ограничения запросов" (limit request zones) — для контроля трафика по различным параметрам.

Пример настройки (реверс-прокси с зоной ограничения запросов):

limit_req_zone $binary_remote_addr zone=limitreqsbyaddr:20m rate=15r/s;
limit_req_status 429;

upstream app.localhost {
 server localhost:8080;
}


server {
 listen 443 ssl;
 server_name app.devlab.intern;

 location / {
  limit_req zone=limitreqsbyaddr burst=10;
  proxy_pass http://app.localhost;
 }
}

Пояснение параметров:

  • $binary_remote_addr

Используется для настройки зоны ограничения по IP-адресу клиента. Адрес сохраняется в бинарной форме, что снижает потребление памяти.

  • zone=limitreqsbyaddr:20m

Создаёт общую (shared) область памяти объёмом 20 МБ с именем limitreqsbyaddr. В этой зоне хранятся данные о лимитах для разных IP-адресов.

  • rate=15r/s

Ограничивает количество запросов до 15 запросов в секунду на IP. Превышение лимита приводит к отклонению избыточных запросов.

  • limit_req_status 429;

При превышении лимита Nginx возвращает статус 429 Too Many Requests, что означает: "Слишком много запросов за короткое время".

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

Ограничение только на необходимые HTTP-методы

На мой взгляд, ограничение допустимых HTTP-методов только теми, которые действительно необходимы или поддерживаются приложением (например, REST API), — это чистый и логичный способ синхронизации настроек веб-сервера с логикой приложения. Это помогает не только предотвратить неправильное использование API или вызов нежелательных методов, но и блокирует потенциально опасные запросы вроде TRACE. Кроме того, это снижает ненужную нагрузку на сервер, устраняя неподдерживаемые или неуместные запросы.

Пример: разрешён только метод GET (HEAD разрешается по умолчанию):

# HEAD is implicit
limit_except GET { 
 deny  all;
}

Пример: разрешить все методы, кроме TRACE и PATCH:

if ($request_method ~ ^(PATCH|TRACE)$) {
 return 405;
}

Простая защита от ботов

Если на сервер поступают запросы от ботов или плохо сконфигурированных сканеров (часто с «говорящими» user-agent'ами), можно внести путаницу и затруднить их работу, возвращая нестандартный статус HTTP от самого Nginx.

Для этого создаём файл bot.protection.conf в директории /etc/nginx/snippets со следующим содержимым:

map $http_user_agent $blacklist_user_agents {
   ~*wpscan            1;
   ~*dirbuster         1;
   ~*gobuster          1;
}

Вы можете дополнять список по мере необходимости.

Внутри конфигурации виртуального хоста (VHost) подключите файл следующим образом:

include /etc/nginx/snippets/bot.protection.conf;

if ($blacklist_user_agents) {
 return 444;
}

HTTP 444 также можно «весело» использовать для предотвращения угадывания служебных файлов, таких как .env:

# <your-domain>/.bash_history for example ends with HTTP 444. 
location ~ /\. {
 return 444;
}

Что означает HTTP 444?

HTTP 444 — это нестандартизированный статус-код, используемый в NGINX, который заставляет сервер мгновенно закрыть соединение без отправки заголовков ответа клиенту. Чаще всего используется для отклонения вредоносных или некорректно оформленных запросов. Интересный побочный эффект: некоторые сканеры не умеют корректно обрабатывать такие ответы, что добавляет дополнительный уровень защиты.

Включение TCP Fast Open

TCP Fast Open — это важное улучшение в Nginx, которое позволяет более эффективно устанавливать TCP-соединения. Эта функция даёт возможность начать передачу данных уже во время начального рукопожатия, что заметно ускоряет процесс установления соединения. Особенно полезна она в условиях высокой сетевой задержки, так как помогает сократить латентность и повысить производительность.

Проверка поддержки TCP Fast Open в ядре Linux

Выполните следующую команду:

cat /proc/sys/net/ipv4/tcp_fastopen

Если в ответе вернётся 1, функция уже включена. Если нет — включите её командой:

echo 1 > /proc/sys/net/ipv4/tcp_fastopen

Использование в конфигурации Nginx

Добавьте параметр fastopen в директивы listen:

 listen [::]:443 ssl http2 fastopen=500;
 listen 443 ssl http2 fastopen=500; 

Число 500 — это количество подключений, которые могут использовать TCP Fast Open одновременно (значение можно адаптировать под вашу нагрузку).

Сжатие с помощью GZip

GZip — это метод сжатия данных, позволяющий уменьшить размер файлов. При этом исходные данные можно полностью восстановить путём распаковки («разархивирования») сжатого файла.

Для веб-приложений и сайтов GZip особенно важен, поскольку HTTP-протокол поддерживает передачу данных в сжатом виде до того, как они попадут в сеть.

Почему GZip важен:

  • Снижение трафика: при включённом GZip размер передаваемых файлов уменьшается, что приводит к меньшему потреблению пропускной способности.
  • Экономия на хостинге: меньше трафика — ниже затраты на обслуживание.
  • Ускорение загрузки для пользователей: посетители получают более лёгкие файлы, что сокращает время загрузки страниц.

Пример конфигурации:

 gzip on;
 gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript;

Эта настройка включает GZip и указывает типы содержимого, которые следует сжимать (текст, CSS, JavaScript, XML, JSON и др.).

Report Page