Nginx безопасность: чек-лист на 2026 без воды
Давай сразу зафиксируем модель. Безопасность шлюза - это не один add_header, а слои. Снаружи внутрь: транспорт (TLS), заголовки ответа (что браузер разрешит делать), фильтрация запроса (методы, размер тела, флуд), сокрытие внутренностей (версии, апстрим-ошибки, dotfiles), скорость (rate limiting против перебора), и наконец гигиена софта (актуальные версии против CVE). Пропустишь слой - получишь компрометацию именно через него.
Пройдёмся по пунктам, каждый с реальной директивой и пояснением почему, а не только как.
1. Транспорт: только TLS 1.2/1.3 и сильные группы. SSLv3, TLS 1.0/1.1 мертвы - POODLE, BEAST. Оставляй два протокола. Помни выверенный факт: ssl_ciphers НЕ управляет шифрами TLS 1.3 - там фиксированный набор AEAD, а тонкая настройка идёт через ssl_conf_command Ciphersuites. И добавь пост-квантовый обмен ключами - в 2026 это уже не экзотика, Chrome и Firefox его шлют по умолчанию.
Код: Выделить всё
ssl_protocols TLSv1.2 TLSv1.3;
ssl_prefer_server_ciphers off; # для TLS1.3 порядок не нужен, клиенту виднее
ssl_ciphers ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305;
ssl_ecdh_curve X25519MLKEM768:X25519:prime256v1; # гибридный post-quantum, OpenSSL 3.5+
ssl_session_cache shared:SSL:50m;
ssl_session_tickets off; # без ротации ключей тикеты ломают forward secrecy
ssl_conf_command Ciphersuites TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256;
2. HSTS - заставь браузер ходить только по HTTPS. Без HSTS первый запрос клиента уйдёт по http и его перехватят (SSL stripping).
Код: Выделить всё
add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload" always;
3. CSP вместо устаревшего X-XSS-Protection. Вот частая ошибка-копипаст из старых гайдов (она есть и в нашем эталонном global_security.conf как наследие). X-XSS-Protection в 2026 устарел - OWASP прямо говорит: не слать его или слать '0'. Старый XSS-аудитор браузеров сам стал источником уязвимостей и давно удалён. Защита от XSS сегодня - это Content-Security-Policy.
Код: Выделить всё
add_header Content-Security-Policy "default-src 'self'; script-src 'self'; object-src 'none'; frame-ancestors 'self'; base-uri 'self'" always;
add_header X-Content-Type-Options "nosniff" always;
add_header Referrer-Policy "no-referrer" always;
add_header Permissions-Policy "geolocation=(), microphone=(), camera=()" always;
# X-XSS-Protection НЕ шлём (или "0") - он устарел в 2026
4. server_tokens off и сокрытие версии. По умолчанию nginx пишет точную версию в заголовок Server и на страницах ошибок. Это подарок сканеру: версия -> список CVE -> готовый эксплойт.
Код: Выделить всё
server_tokens off;
5. max_headers - анти-флуд заголовками (nginx 1.29.8). Свежая директива. Раньше ничто не мешало клиенту прислать тысячи мелких заголовков в одном запросе - это header-flooding DoS, который ел память и CPU воркера. Теперь есть жёсткий потолок:
Код: Выделить всё
max_headers 100; # запрос с большим числом заголовков -> сразу 400 Bad Request

Nginx hardening: фильтрация запроса и сокрытие внутренностей
Теперь слой запроса. Тут живут самые дешёвые в эксплуатации дыры.
6. Запрет dotfiles, .git, .env и бэкапов. Классика утечек: выложили проект rsync-ом вместе с .git, и любой выкачивает исходники и секреты через /.git/config. Или .env с паролем БД лежит в корне сайта.
Код: Выделить всё
location ~ /\.(?!well-known) { # любые dotfiles, кроме .well-known (ACME, security.txt)
deny all;
access_log off;
log_not_found off;
}
location ~* \.(env|bak|sql|zip|tar|gz|old|swp|orig)$ {
deny all;
}
7. client_max_body_size - потолок тела запроса. По умолчанию 1m. Если у тебя загрузка файлов - подними точечно на нужном location, но НЕ ставь глобально гигабайты: бесконечный POST это и DoS, и переполнение диска во временных файлах.
Код: Выделить всё
client_max_body_size 1m; # глобально жёстко
location /api/upload/ {
client_max_body_size 20m; # послабление только там, где реально нужно
}
Код: Выделить всё
location /api/read/ {
limit_except GET HEAD { deny all; } # всё кроме GET/HEAD -> 403
}
# глобальный белый список методов (как в эталонном http_server.conf):
if ($request_method !~ ^(GET|HEAD|POST)$ ) { return 405; }
9. Сокрытие апстрим-ошибок. Когда бэкенд падает с 500 и стектрейсом, нельзя отдавать это клиенту - там пути, версии фреймворка, иногда SQL. Перехватывай и подменяй своей страницей.
Код: Выделить всё
proxy_intercept_errors on;
error_page 500 502 503 504 /errors/50x.html;
location = /errors/50x.html { internal; root /usr/share/nginx/html; }
10. Никакого autoindex на проде. autoindex on показывает листинг каталога - то есть отдаёт карту всех файлов любому. По умолчанию off, но его иногда включают для отладки и забывают. Проверь, что нигде нет лишнего autoindex on. В эталоне он явно autoindex off.
11. Правильный realip - иначе спуфинг X-Forwarded-For. Это пункт, который ломают чаще всего. Если перед nginx стоит CDN/балансировщик, то $remote_addr - это адрес прокси, НЕ клиента. Ты подключаешь realip, чтобы вытащить настоящий IP из X-Forwarded-For. Но если доверять этому заголовку от КОГО УГОДНО, клиент сам пришлёт X-Forwarded-For: 127.0.0.1 и обойдёт твой allow/rate-limit/гео.
Код: Выделить всё
set_real_ip_from 10.0.0.0/8; # ТОЛЬКО реальные сети твоих прокси/CDN
set_real_ip_from 173.245.48.0/20; # пример: диапазон Cloudflare
real_ip_header X-Forwarded-For;
real_ip_recursive on; # пройти цепочку справа налево, отбросить доверенные
12. Анти-Slowloris таймауты. Slowloris - атака, где клиент открывает соединения и шлёт заголовки/тело по байту в час, держа воркеры занятыми. Лечится таймаутами на медленных стадиях.
Код: Выделить всё
client_header_timeout 10s; # сколько ждём полный набор заголовков
client_body_timeout 10s; # сколько ждём тело
send_timeout 10s; # таймаут на отправку ответа клиенту
keepalive_timeout 30s;
13. Rate limiting на чувствительных эндпоинтах. Логин, восстановление пароля, OTP - всё, что перебирают. В эталоне для этого отдельные зоны: app_login 5r/s, security_sensitive 1r/s.
Код: Выделить всё
limit_req_zone $binary_remote_addr zone=app_login:10m rate=5r/s;
location /api/login {
limit_req zone=app_login burst=5 nodelay;
proxy_pass http://backend_upstream;
}
14. Минимизация rewrite-правил. Это не только про читаемость. Связано напрямую со свежим CVE (следующая секция): уязвимость живёт именно в ngx_http_rewrite_module. Чем меньше у тебя сложных rewrite с PCRE-захватами и знаками вопроса в замене, тем меньше поверхность атаки. Где можно - заменяй rewrite на try_files, return, map. Это и быстрее, и безопаснее.
Nginx CVE 2026: гигиена версий, которую нельзя игнорировать
Конфиг можно вылизать идеально, но если бинарь дырявый - всё зря. 2026 выдался жарким. Запоминай эти четыре CVE и минимально безопасные версии.
CVE-2026-42945 - NGINX Rift. Главная боль года. Heap buffer overflow в ngx_http_rewrite_module. Затронуты ВСЕ версии от 0.6.27 (2008 год!) до 1.30.0 включительно. CVSS 4.0 - 9.2, критический. Механика: при rewrite-правиле, где безымянный PCRE-захват комбинируется со знаком вопроса в замене, флаг состояния is_args, выставленный на фазе подсчёта длины, протекает в фазу копирования - и ngx_escape_uri пишет за пределы буфера. Триггерится ОДНИМ запросом без аутентификации. Минимум - перезапуск воркера (DoS), при отключённом ASLR возможен и RCE. Эксплуатируется в дикой природе с мая 2026.
Лечение: обнови на nginx 1.30.1 (stable) или 1.31.0+ (mainline). freenginx и Angie выпустили свои патчи. И минимизируй rewrite-правила (пункт 14) как defense-in-depth.
CVE-2026-1642 - инъекция ответа от апстрима. При MITM между nginx и бэкендом атакующий может подмешать в ответ апстрима лишние заголовки/тело (response splitting). Защита - TLS до апстрима там, где канал не доверен, и обновление.
CVE-2026-40460 - HTTP/3 connection migration spoofing. Если у тебя включён QUIC/HTTP/3, баг в миграции соединения позволяет подделать адрес. Держи nginx с HTTP/3 строго обновлённым.
CVE-2026-8711 - heap overflow в njs js_fetch. Касается тех, кто использует njs с Fetch API. Обнови njs-модуль.
Вывод простой и жёсткий: держи nginx и ВСЕ динамические модули (njs, otel, brotli) обновлёнными. Сторонние модули обновляются отдельно от ядра - про них забывают. Проверяй текущую версию и сравнивай с минимально безопасной:
Код: Выделить всё
nginx -v
# nginx version: nginx/1.30.1 <- ниже 1.30.1 в stable-ветке = уязвим к Rift
nginx -V 2>&1 | tr ' ' '\n' | grep -i module # какие модули вкомпилены
Глазами всё это не уследить. Поэтому финальный шаг - автоматический аудит. Три инструмента, которые должны стать рутиной.
gixy - статический анализатор nginx.conf. Изначально написан в Yandex, сейчас активно поддерживается форк gixy-ng (на PyPI). Делает 30+ проверок: SSRF через proxy_pass с переменной, HTTP response splitting, небезопасный add_header (который, кстати, ОБНУЛЯЕТ унаследованные заголовки на своём уровне - частая дыра!), проблемы с regex в location. Запуск:
Код: Выделить всё
pip install gixy-ng
gixy /etc/nginx/nginx.conf
Код: Выделить всё
==================== Results ===================
>> Problem: [add_header_redefinition] Nested "add_header" drops parent headers.
Description: "add_header" replaces ALL inherited headers from the parent level.
Severity: HIGH
Pseudo config:
server {
add_header Strict-Transport-Security ...;
location / {
add_header X-Frame-Options SAMEORIGIN; # тут HSTS ПОТЕРЯЛСЯ
}
}
==================== Summary ===================
Total issues: Unspecified: 0 Low: 1 Medium: 0 High: 1
testssl.sh и SSL Labs - аудит TLS. testssl.sh гоняешь локально по любому порту, он проверит протоколы, шифры, известные крипто-баги (ROBOT, Heartbleed), цепочку, HSTS.
Код: Выделить всё
./testssl.sh --quiet --color 0 https://cyberlake.ru
securityheaders.com - аудит заголовков ответа. Вбиваешь домен, получаешь оценку по CSP, HSTS, X-Content-Type-Options и компании. Быстрый способ убедиться, что секция из пунктов 2-3 реально доехала до браузера (и не съелась add_header-redefinition).
WAF-слой как усиление. Поверх всего этого ставится WAF - ModSecurity с набором правил OWASP CRS (Core Rule Set). Он ловит SQLi/XSS/path traversal на уровне сигнатур ещё до бэкенда. В эталонном app_redirects_security.conf есть упрощённые ручные фильтры (union select, ../, GLOBALS) - это бедняцкий WAF на регэкспах. Для серьёзного прода - полноценный ModSecurity+CRS, но помни про ложные срабатывания: гоняй сначала в DetectionOnly-режиме.
Мини-лаба: прогони свой конфиг через аудит
Повтори руками по шагам на тестовом стенде.
- Шаг 1. Проверь версию: nginx -v. Если ниже 1.30.1 (stable) - ты уязвим к NGINX Rift. Запланируй обновление.
- Шаг 2. Поставь анализатор: pip install gixy-ng, затем gixy /etc/nginx/nginx.conf. Выпиши все High и Medium находки.
- Шаг 3. Найди в конфиге хоть один location с собственным add_header. Убедись через gixy или curl -I, что security-заголовки с server-уровня там не потерялись. Если потерялись - вынеси заголовки в include и подключи на каждом уровне, либо собери все add_header в одном месте.
- Шаг 4. Добавь в server max_headers 100; client_header_timeout 10s; client_body_timeout 10s;. Проверь nginx -t и reload.
- Шаг 5. Заблокируй dotfiles регэкспом из пункта 6. Проверь: curl -I http://localhost/.git/config должен вернуть 403.
- Шаг 6. Прогони внешний аудит: testssl.sh по своему домену и ssllabs.com/ssltest. Добейся оценки A или A+. Затем securityheaders.com - закрой пробелы по заголовкам.
- Шаг 7. Проверь realip: если перед тобой прокси, убедись, что set_real_ip_from содержит ТОЛЬКО сети прокси, а в логах $remote_addr показывает реальный клиентский IP, а не адрес балансировщика.
- Почему set_real_ip_from 0.0.0.0/0 - это дыра, и что именно сможет подделать клиент?
- В чём суть CVE-2026-42945, какие версии затронуты и до какой версии надо обновиться в stable-ветке?
- Почему X-XSS-Protection в 2026 не нужен, и что его заменяет?
- Что делает add_header внутри location с заголовками, заданными на server-уровне, и как gixy помогает это поймать?
Безопасность nginx - это слои, и каждый закрывается конкретной директивой: TLS 1.2/1.3 с пост-квантовыми группами, HSTS и CSP (без устаревшего X-XSS-Protection), server_tokens off, свежий max_headers против флуда, запрет dotfiles, потолки тела и таймауты против Slowloris, верный realip против спуфинга XFF, rate limit на чувствительных эндпоинтах и минимум rewrite. Поверх - гигиена версий: NGINX Rift и компания CVE 2026 лечатся обновлением на 1.30.1+. И не доверяй глазам - прогоняй конфиг через gixy, TLS через testssl.sh и SSL Labs, заголовки через securityheaders.com. Сделай этот чек-лист частью CI - и твой gateway перестанет быть одной забытой директивой от компрометации.