Запрет доступа по IP адресу к веб-серверу Nginx без указания домена сайта
В некоторых случаях возможность доступа к веб-серверу напрямую через IP адрес является серьезной уязвимостью. Необходимо повысить приватность и безопасность веб-сервера nginx, чтобы когда пользователь или бот зайдет по IP адресу через HTTP или HTTPS, то там не будет никакой полезной информации и будет выведена ошибка или соединение вовсе будет закрыто.
В первой половине статьи будет продемонстрирована конфигурация nginx без использования серверов по умолчанию и к чему может привести подобная конфигурация веб-сервера.
Если ты ленивый или у тебя мало времени, то переходи сразу ко второй части статьи. В ней показан процесс создания серверов по умолчанию и разрешения доступа к веб-серверу nginx только по доменным именам сайтов.
1. Конфигурация nginx без использования серверов по умолчанию (параметр default_server)
1.1. Пример файла конфигурации nginx.conf и сайта
Так выглядит конфигурационный файл nginx.conf без указания блоков server по умолчанию:
# Пример минимальной базовой конфигурации nginx без использования параметра default_server
worker_processes auto;
events {
worker_connections 1024;
}
http {
include mime.types;
default_type application/octet-stream;
access_log off;
# Настройка блоков server для каждого сайта в отдельном файле конфигурации.
include conf/*.conf;
}
В каталоге conf/ находятся конфигурационные файлы для каждого сайта, который обсуживает данный сервер nginx. Блоки server для сайтов могут находится сразу в nginx.conf (основной конфигурационный файл nginx).
Например, файл конфигурации для сайта notby.net выглядит так:
# Блок server для доступа к сайту по HTTP (80 порт)
server {
listen 80; # Порт сервера.
server_name notby.net; # Домен сайта.
#Перенаправление всего трафика с http на https
location / {
return 301 https://$host$request_uri;
}
}
# Блок server для доступа к сайту по HTTPS (443 порт)
server {
listen 443 ssl; # 443 порт, поддержка SSL.
http2 on; # Разрешить использовать HTTP/2.
server_name notby.net; # Домен сайта.
# Пути к списку сертификатов и настройка SSL
ssl_certificate /usr/local/etc/letsencrypt/live/notby.net/fullchain.pem;
ssl_certificate_key /usr/local/etc/letsencrypt/live/notby.net/privkey.pem;
ssl_trusted_certificate /usr/local/etc/letsencrypt/live/notby.net/chain.pem;
ssl_protocols TLSv1.3; # Разрешенные протоколы (только TLS 1.3).
ssl_prefer_server_ciphers off; # Использовать клиентские шифры.
ssl_stapling on; # Обязательна ssl_trusted_certificate директива.
ssl_stapling_verify on;
location / {
root /usr/local/www/notby.net/; # Каталог сайта.
index index.html index.php; # Файлы в качестве индекса.
}
}
Если у директивы listen есть параметр default_server, то сервер, в котором описана эта директива, будет сервером по умолчанию для указанной пары адрес:порт. Если же директив listen с параметром default_server нет, то сервером по умолчанию будет первый сервер, в котором описана пара адрес:порт.nginx: документация (модуль ngx_http_core_module)
В таком случае, сервером по умолчанию будет первый по алфавиту конфигурационный файл в котором описана переменная listen и для нее указан порт или адрес:порт.
1.2. Проверка доступа к nginx через IP адрес
Допустим, первыми серверами для HTTP и HTTPS будут блоки server для сайта из примера выше.
Через утилиту cURL или через веб-браузер зайдем на свой веб-сервер по IP адресу с использованием HTTP протокола
curl -I http://80.95.110.25
Произошло перенаправление на HTTPS. Но, если в настройке сервера для сайта не будет перенаправления, то может открытся веб-сайт по IP адресу.
Теперь зайдем с использованием HTTPS протокола. Добавим параметр v для утилиты cURL, чтобы вывести более детальную информацию и сведения о сертификате
curl -vI https://80.95.110.25
Выведена информация о сертификате, в частности доменное имя сайта. Значит, что на этом IP находится данный сайт. В плане приватности и безопасности в скрытии этой информации смысла нет, так как через DNS будет и так видно сайты, которые находятся на данном IP адресе. Не совсем правильно выдавать подобную информацию при доступе через IP адрес и это надо исправить.
Когда сайт находится за провайдером CDN в режиме использования сертификатов для HTTPS с оригинального веб-сервера, то получается что сайт имеет IP адрес провайдера CDN и проверка через DNS покажет IP адрес CDN провайдера. Сторонний человек не сможет определить через DNS реальный IP адрес дата-центра, провайдера VDS где находится веб-сайта.
Это является критической уязвимостью приватности и безопасности в обрисованном выше случае. Так как при запросе через IP адрес веб-сервера, будет выдана информация о сертификате, в частности доменное имя сайта и сведения о владельце.
Если зайти через веб-браузер, то будет выведено сообщения о неподходящем сертификате и для какого сайта он действителен
Посмотреть сертификат веб-сервера можно нажав для этого на ссылку Просмотреть сертификат. Если нажать Принять риск и продолжить, то откроется веб-сайт через IP адрес.
2. Конфигурация nginx с указанием серверов по умолчанию (параметр default_server)
В конфигурации nginx блок server становится по умолчанию, если к директиве listen добавлен параметр default_server. Необходимо создать два блока server и сделать их серверами по умолчанию для 80 порта и 443 порта соответственно. В этих блоках нужно ограничить доступ к веб-серверу по IP адресу без указания домена сайта.
Блок сервера по умолчанию для HTTP протокола (80 порт) с запретом доступа и сбросом входящего соединения:
server {
listen 80 default_server; # Сервер по умолчанию для 80 порта.
deny all; # Запретить доступ всем.
return 444; # Закрыть соединение без ответа.
}
Блок сервера по умолчанию для HTTPS протокола (80 порт) с отклонением операций SSL handshake (рукопожатия) и закрытием соединения:
server {
listen 443 ssl default_server; # Сервер по умолчанию для 443 порта.
http2 on; # Разрешить использовать HTTP/2.
ssl_reject_handshake on; # Отклонить рукопожатие.
}
Эти два блока необходимо добавить в файл конфигурации nginx.conf своего веб-сервера.
2.1. Пример файла конфигурации nginx.conf
Так выглядит конфигурационный файл nginx.conf с указанием блоков server по умолчанию для 80 и 443 портов:
# Пример минимальный базовой конфигурации nginx с указанием параметра default_server
# и пояснением переменных внутри блоков server.
worker_processes auto;
events {
worker_connections 1024;
}
http {
include mime.types;
default_type application/octet-stream;
access_log off;
# Сервер по умолчанию для HTTP (80 порт)
server {
# В директиве listen указан только 80 порт и параметр default_server,
# значит этот блок server по умолчанию для всех сетевых интерфейсов.
listen 80 default_server;
# Запретить доступ всем, указан для безопасности.
deny all;
# Переменная return отправляет код ответа HTTP.
# Чтобы закрыть соединение без отправки ответа, использовать 444 код.
return 444;
# Вместо 444 можно указать любой код 404 или любой другой.
#return 404;
}
# Сервер по умолчанию для HTTPS (443 порт)
server {
# В директиве listen указан только 80 порт и параметры ssl, default_server,
# значит этот server по умолчанию для всех сетевых интерфейсов.
listen 443 ssl default_server;
# Разрешить использовать HTTP/2.
http2 on;
# Операции SSL handshake будут отклонены и соединение закрыто.
ssl_reject_handshake on;
# Указать глобально для всего сервера версию протокола защиты HTTPS.
# Если в другом блоке для сайта указать TLSv1.2, она не сработает.
ssl_protocols TLSv1.3;
}
# Настройка блоков server для каждого сайта в отдельном файле конфигурации.
include conf/*.conf;
}
Если в блоке server для HTTPS не указывать директиву ssl_reject_handshake, то при запуске веб-сервера будет выведена ошибка nginx: [emerg] no "ssl_certificate" is defined for the "listen ... ssl" directive in nginx.conf и он не запустится. Директива ssl_reject_handshake была специально добавлена для подобной задачи в версии nginx 1.19.4.
2.2. Проверка безопасности nginx при доступе через IP адрес
Через утилиту cURL или через веб-браузер зайдем на свой веб-сервер по IP адресу с использованием HTTP протокола
curl -I http://80.95.110.25
В случае указания кода 444 соединение было закрыто сразу и был получен пустой ответ от сервера. Если использовать код 404, будет выведено стандартное сообщение, что запрашиваемая страница не найдена.
Теперь зайдем с использованием HTTPS протокола. Добавим параметр v для утилиты cURL, чтобы вывести более детальную информацию
curl -vI https://80.95.110.25
Веб-сервер сбросил соединение и нечего не ответил на рукопожатие клиента. Информация для нарушения приватности и безопасности передана не была, даже не известно, что за веб-сервер.
Если зайти через веб-браузер, то будет выведено сообщение об ошибке защищённого соединения
Веб-браузер не смог соединится и распознал это как ошибку SSL_ERROR_UNRECOGNIZED_NAME_ALERT, никакая информация передана не была.