Как настроить Nginx для защиты от атак и уязвимостей
Обычно это происходит из-за таких уязвимостей, как RCE (удаленное исполнение кода), SSRF (подделка запросов на стороне сервера) и CSRF (межсайтовая подделка запроса).
И такие атаки – не редкость.
По данным центра исследования киберугроз Solar 4RAYS, во втором квартале 2025 года число обнаруженных уязвимостей в популярных веб-приложениях выросло на 58% по сравнению с предыдущим кварталом, а решения “Лаборатории Касперского” ежедневно обнаруживают 500 тыс. новых вредоносных файлов.
Чтобы избежать атак или как минимум сократить последствия, важно грамотно настроить сервер.
В этой статье разбираем, как можно снизить угрозу уязвимостей и атак на Nginx – самый популярный веб-сервер в мире.
Итак, вот наш топ рекомендаций для защиты Nginx.
Проверьте файлы, доступные публично
При типовой конфигурации для работы с PHP конфигурация выглядит так:
location / { try_files $uri $uri/ /index.php?$args; }Директива try _files выполняется слева направо, то есть при запросе сначала проверяется доступность файла из запроса – и, при его наличии, он будет отдан. Это базовый функционал веб-сервера, но таким образом можно извне прочитать различные файлы конфигурации в папке приложения, файлы версий Composer, .bak, .sql и т. д., о которых разработчик не задумывается.При использовании Composer, кроме доступа к файлам версий, при неверной конфигурации существует возможность запуска PHP-файлов зависимостей из папки “vendor” напрямую. Иногда зависимости содержат файлы примеров, скриптов или различных модулей, не задействованных в основном приложении, с помощью которых возможно исполнение кода или отображение произвольного текста, открывающее возможность для проведения CSRF-атак.Внимательно относитесь к файлам, которые становятся доступны публично, – храните приватные данные вне web-root, отключайте листинг директорий и явно ограничивайте доступ к чувствительным типам файлов через deny all или точные правила try_files.
Переменные в proxy_pass
proxy_pass используется для перенаправления запросов с веб-сервера на другой сервер и указывает на путь или URL, на который проксируется запрос, полученный Nginx.
Рассмотрим такую конфигурацию:
location / { proxy_pass http://$http_host$request_uri; }Мы рекомендуем быть аккуратными с использованием переменных в proxy_pass, поскольку если на их содержимое может влиять злоумышленник (например, как в примере выше, когда содержимое $http_host и $request_uri берется из HTTP-запроса), это дает возможность организовать атаку типа SSRF – отправлять запросы внутренним сервисам.
Грамотным решением может стать исключение использования непроверенных переменных в proxy_pass. Если есть возможность, вместо подстановки $http_host задавайте фиксированный целевой адрес или применяйте строгую валидацию и маппинг допустимых хостов.
Будьте осторожны со слешами
При лишних слешах можно вставить “..” – и получить доступ туда, куда разработчик приложения не предполагал предоставлять доступ.
При такой конфигурации:
location /static { alias /home/app/static/; }Если мы выполним запрос:
GET /static../settings.pyСервер Nginx достаточно прямолинейно обработает запрос и добавит‘../settings.py’к значению директивы alias:
/home/app/static/../settings.pyТаким образом можно получить доступ за пределы ожидаемой разработчиком папки.
Так же это работает и с другими директивами, такими как proxy_pass:
location /api { proxy_pass http://apiserver/v1/; }Так можно выйти за пределы ожидаемого сегмента адреса (v1 в нашем случае). Например, если в качестве проксируемого сервера используется Apache, то данным запросом можно раскрыть его статусную страницу.
GET /api../server-statusApache получит запрос: http://apiserver/v1/../server-status
Старайтесь использовать root вместо alias, если структура приложения позволяет, и валидируйте пути на стороне проксируемого сервера.
Будьте аккуратны с FastCGI
Когда Nginx передает запросы с помощью протокола FastCGI, каждое сообщение FastCGI содержит набор переменных среды. Поэтому настройка Nginx должна включать проверку, какие переменные среды передаются через директивы fastcgi_param, – чтобы избежать исполнения кода или раскрытия данных, не предусмотренных разработчиком.
Например, безобидная конфигурация:
location / { try_files $uri $uri/ /index.php?$args; } location ~ \.php$ { fastcgi_pass ...; fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name; include fastcgi_params; }Для URL, оканчивающихся на .php, Nginx не будет проверять существование файла и слепо передаст в переменной SCRIPT_FILENAME нормализованный путь из запроса. В зависимости от типа и версии вашего FastCGI-бэкенда, типа операционной системы, используемой локали, файловой системы, а также конфигурации самого Nginx, существуют различные способы манипуляций с адресом для исполнения кода, не предусмотренного разработчиком.
Переменная SCRIPT_FILENAME будет доступна в PHP $_SERVER[‘SCRIPT_NAME’]. Если она или ее производные выводятся на страницу без экранирования, то злоумышленник может вставить в адресную строку вредоносный код, который отобразится на странице в оригинальном виде.
Так же, например, можно вставить пробел, слеш, null-символ или другие спецсимволы в адрес, чтобы FastCGI-бэкенд исполнил не тот файл, который указан в адресе.
Классический пример:
GET /upload/avatar.jpg/.phpNginx передаст этот запрос FastCGI-бэкенду, а код из avatar.jpg может быть исполнен как скрипт (или, в зависимости от бэкенда, отдан как текст).
В современном PHP-FPM директива security.limit_extensions содержит список допустимых расширений файлов для исполнения и должна предотвратить конкретно этот сценарий, но нужно быть аккуратными с другими FastCGI-бэкендами, а также при более пермиссивной настройке security.limit_extensions (например, часто туда добавляют .inc).
Чтобы не передавать лишние запросы, можно проверять наличие файлов в самом Nginx:
{ try_files $uri =404; fastcgi_pass …; }Будьте осторожны с переменными
$uri и $document_uri – это нормализованные переменные, то есть последовательность вида %0d%0a декодируется в реальные символы переноса строки (CRLF).
Таким образом в подобной конфигурации можно вставить неожиданный перенос строки и дописать свои заголовки:
location /static/ { return 302 http://172.17.0.1$uri; }GET/static/%0d%0aX-Foo:%20CRLFNginx вернет:
HTTP/1.1 302 Moved Temporarily ... Location: http://172.17.0.1/static/ X-Foo: CRLFДля защиты от подобных CSRF в Nginx важно тщательно управлять заголовками, которые могут быть применены злоумышленниками, использовать безопасные переменные вроде $request_uri, а также merge_slashes on – чтобы исключить обход правил через манипуляции с URL.
Конфигурация SSL должна быть надежной
Мы рекомендуем не играть в криптографа и использовать надежные средства для конфигурации SSL – например, Mozilla SSL Configuration Generator. Так можно предотвратить MITM-атаки, при которых злоумышленник перехватывает и потенциально изменяет коммуникацию между сторонами, что позволяет ему просматривать содержимое всех передаваемых ими сообщений, удалять и изменять их.
Заключение
Любые атаки – серьезная угроза для сайтов и приложений, а защита от них требует комплексного подхода. В этой статье мы разобрали неочевидные нюансы, которые стоит учесть при настройке Nginx, при этом для защиты VPS-сервера могут быть полезны и другие способы.
Например, если ваша инфраструктура находится в облаке, можно использовать CDN– сеть доставки контента, которая обеспечит дополнительную защиту от атак благодаря переводу запросов к контенту на серверы CDN.
Если у вас возникли вопросы, свяжитесь с нами удобным для вас способом – и мы обязательно ответим. Также ждем вас в нашем официальном Telegram-канале, а пообщаться на любую тему с коллегами по цеху и сотрудниками Beget вы можете в нашем чате.
Лучшее в блогах
Вам понравится
Разбираем ключевые метрики монетизации сайтов: CPM, RPM, RPS, Viewability, Fill Rate, CTR и IVT. Почему высокий CPM не гарантирует высокий доход и как правильно оптимизировать рекламу? Пошагово в статье, как увеличить RPM и прибыль сайта без роста трафика.
Неделя рекламы
Энциклопедия обмана