Назад | Перейти на главную страницу

Nginx отвечает 200, даже если заголовок HTTP HOST отличается от SNI

Я только начал изучать nginx и SSL и не пытался использовать разные конфигурации. У меня есть два серверных блока, например:

server{
    listen 443 ssl http2;
    server_name www.a.com;
    ssl_certificate a.crt;
    ssl_certificate_key a.key;
    ....
}
server{
    listen 443 ssl ;
    server_name www.b.com;
    ssl_certificate b.crt;
    ssl_certificate_key b.key;
    ....
}

После подключения к nginx через openssl s_client с использованием www.a.com в качестве SNI я отправил запрос GET с помощью Host: www.b.com, и он все еще работает. Ожидается ли это? Может ли кто-нибудь помочь мне понять поведение nginx?

HTTP-соединение - это просто TCP-соединение в конце концов. Таким образом, приведенное выше на самом деле подходит для HTTP-соединений (т.е. если вы подключаетесь к www.a.com, вы фактически подключаетесь к IP-адресу, а не к www.a.com, поэтому на самом деле это нормально и ожидается, что это соединение сможет адресные запросы для www.b.com).

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

Для HTTP / 1.1 в HTTP через TLS RFC ни Протокол передачи гипертекста (HTTP / 1.1): синтаксис сообщений и маршрутизация RFC, чтобы указать, как это должно быть обработано, поскольку SNI является необязательным расширением HTTP, добавленным после (фактически, помимо этого, это был один из способов обойти клиентов - например, IE8 в XP - если один и тот же сертификат используется для обоих виртуальные хосты, то соответствующее соединение может использоваться после согласования сеанса TLS на основе этого сертификата, предоставленного хостом по умолчанию). Однако В SNI RFC четко указано, что сервер ДОЛЖЕН проверить, что это то же самое, поэтому, когда имя сервера указано и отличается от имени хоста, то, что вы наблюдаете, неверно (спасибо Майклу Хэмптону за указание на это, поскольку я пропустил это изначально).

HTTP / 2 более ясен в этом и фактически допускает повторное использование соединения в определенных условиях и должен это сказать:

Соединение можно использовать повторно, если исходный сервер является авторитетным (раздел 10.1). Для TCP-соединений без TLS это зависит от того, разрешил ли хост один и тот же IP-адрес.

Для ресурсов https повторное использование соединения дополнительно зависит от наличия сертификата, действительного для хоста в URI. Сертификат, представленный сервером, ДОЛЖЕН соответствовать любым проверкам, которые клиент будет выполнять при формировании нового соединения TLS для хоста в URI.

Исходный сервер может предложить сертификат с несколькими атрибутами subjectAltName или именами с подстановочными знаками, один из которых действителен для органа в URI. Например, сертификат с subjectAltName * .example.com может разрешить использование того же соединения для запросов к URI, начинающимся с https://a.example.com/ и https://b.example.com/.

Так что, если a.crt также включает в себя www.b.com в поле «Альтернативное имя субъекта», то указанное выше действительно подходит для HTTP / 2, но не для HTTP / 1.1.

Однако, чтобы быть уверенным, я повторил ваши наблюдения, когда a.crt определенно НЕ охватывает www.b.com, и это действительно звучит как ошибка, а также потенциально угроза безопасности, поскольку запрос на один виртуальный хост может быть читается другим виртуальным хостом (несмотря на то, что у него нет доступа к ключу, с помощью которого было расшифровано сообщение), если кто-то смог ввести недопустимый заголовок хоста (что, к счастью, с браузерами сделать нелегко, поэтому, по общему признанию, я не могу это продемонстрировать). Это может привести к утечке файлов cookie или другой информации на вторичный сервер.

Я сообщил об этом команде безопасности nginx, которые сказали, что это не проблема безопасности с nginx, и что клиент должен проверять сертификаты, а затем не отправлять искаженные запросы для хостов, к которым они должны получать доступ через это соединение. . Я категорически не согласен с этим и говорю, что весь смысл HTTPS в том, чтобы разрешать расшифровывать сообщения только действительным конечным точкам! Так что, думаю, чек должен быть как на клиенте и на стороне сервера и по сути именно этот сценарий обсуждался рабочей группой TLS в то время, когда SNI был конкретным, поэтому вышеуказанная формулировка была добавлена ​​в RFC. Кроме того, группа безопасности nginx говорит, что в этом сценарии nginx должен быть настроен с общим сертификатом для обоих хостов (что для меня не имеет смысла, так как сильно ограничивает полезность виртуального хостинга в nginx!), Но если оператор сервера nginx действительно хочет ограничить это, тогда они могут сделать это, проверив $ssl_server_name переменная (что для меня означает относительно простую проверку, которую nginx может выполнять по умолчанию!). В любом случае, это их программное обеспечение, и они имеют право на свое мнение, но я не согласен.

Также отмечалось, что этот метод иногда используется для избежания цензуры в процессе, известном как Домен Fronting. Что достаточно справедливо, но я думаю, что это должно быть явно включено, а не разрешено по умолчанию.

Между прочим, Apache не делает то же самое и (правильно ИМХО) возвращает «400 Bad Request» до 2.4.17 и новый «421 (Misdirected Request)» после 2.4.17 - это был новый код состояния HTTP, созданный специально для этого сценария.