Блокировать прямой доступ к IP-адресу веб-сервера через HTTPS

Подобно этот и этот вопрос Я хочу запретить пользователям использовать IP-адрес для доступа к моему серверу .

Для HTTP (порт 80) это работает нормально, но не для HTTPS. Таким образом, пользователи все еще могут ввести https: // для доступа к веб-серверу, а nginx вернет сертификат по умолчанию. Кстати, я использую HTTP2 в своих «обычных» серверных блоках (с моими доменными именами), поэтому я использую:

listen 443 ssl http2;
listen [::]:443 ssl http2;

Я пробовал это, чтобы заблокировать доступ по протоколу HTTPS ip:

server {
   listen 443 ssl;
   listen [::]:443 ssl;

   server_name _;
   return 444;
}

Однако, к сожалению, это блокирует все запросы HTTPS, независимо от того, используется ли домен используется или нет. Я знаю, что может потребоваться заблокировать клиентов, не относящихся к SNI, поскольку они, конечно, не доставляют используемое доменное имя на сервер, поэтому меня это устраивает. (Я имею в виду, что клиенты, не поддерживающие SNI, в любом случае старые ...)

Я обычно предпочитаю блокировать это в nginx, но если у вас есть идеи по блокировке этого на уровне брандмауэра (iptables), я бы тоже с радостью оценил это. . И если вы хотите спорить, почему блокировка с помощью iptables лучше, вы также можете сделать это и убедить меня также блокировать HTTP [или все другие] запросы к IP. В общем, сброс соединения - это нормально (как и код состояния nginx 444).

Однако есть одно требование: я не хочу явно указывать IP-адрес сервера в конфигурации, поскольку это динамический IP-адрес, и сервер использует динамический DNS-сервис.

Вкратце, вот чего я хочу достичь:

  • заблокировать доступ через IP
  • разрешить доступ через доменное имя
  • можно заблокировать клиентов, не относящихся к SNI. блокировка брандмауэром для этого
  • разрыва соединения прекрасна
  • без упоминания IP-адреса сервера
  • без раскрытия доменного имени через HTTPS

Правка: Еще одна неудачная попытка. Я попытался последовать этому предложению и использовать этот фрагмент конфигурации, который логически кажется хорошим:

if ($host != "example.com") {
        return 444;
}

Он также в основном работает, но когда я открываю «https: //», я сначала вижу этот nginx уже отправляет сертификат HTTPS (содержащий доменное имя), и только когда я пропускаю предупреждение о подключении, я вижу, что он блокирует доступ. Это логично, поскольку nginx может читать заголовок Host только при наличии HTTPS-соединения, но в этот момент nginx уже отправляет сертификат сервера, содержащий имя домена, поэтому теперь у пользователя есть имя домена и он может повторно подключиться, используя его, создавая весь IP-адрес. блокировка бесполезна. Меня также немного беспокоит аспект производительности этого решения, поскольку он заставляет nginx проверять заголовок хоста для каждого запроса, поэтому я все еще ищу решение здесь.

7
задан 5 August 2016 в 00:19
2 ответа

Попробуйте это - бит default_server является важной частью. Если это не сработает, обновите свой вопрос, указав конфигурацию для других серверов, прослушивающих 443 / SSL.

server {
  listen 443 ssl default_server;
  listen [::]:443 ssl default_server; # not sure if you want/need it here as well. Try both ways.

 server_name _;
 return 444;
}
2
ответ дан 2 December 2019 в 23:30

Сегодня я столкнулся с той же проблемой с этим блоком:

server {
  listen 443 ssl default_server;
  server_name <SERVER-IP>;
  return 444;
}

В журналах nginx говорится:

"ssl_certificate" не определен в сервере, прослушивающем порт SSL, в то время как Подтверждение связи SSL

Как вы упомянули, похоже, это отключает и другие серверные блоки. Это можно исправить, используя (самоподписанный) сертификат для IP-адреса сервера. Я сделал это с помощью openssl:

openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout privateKey.key -out certificate.crt -subj '/CN=<SERVER-IP>'

Затем измените server-block на:

server {
    listen 443 ssl default_server;
    server_name <server-ip>;
    ssl_certificate         /path/to/certificate.crt;
    ssl_certificate_key     /path/to/privateKey.key;
    return 444;
}

Когда кто-то использует IP-адрес СЕРВЕРА через https для доступа к серверу, nginx представляет (самоподписанный) сертификат, а НЕ имя домена. сертификат, который вы хотите скрыть.

Кстати, сделайте ваш server-block-with-IP default_server. Таким образом, клиент, у которого отключен SNI, получит IP-сертификат, а НЕ сертификат доменного имени. Это также можно проверить с помощью openssl (параметр -servername, который включает SNI, опущен):

openssl s_client -connect <SERVER-IP>:443
8
ответ дан 2 December 2019 в 23:30

Теги

Похожие вопросы