Защита ваших веб-приложений от внедрения уязвимости заголовка Host имеет решающее значение для поддержания безопасности и целостности вашей веб-инфраструктуры. Этот тип уязвимости может быть использован злоумышленниками несколькими способами, включая отравление сброса пароля и отравление веб-кэша, что может привести к широкому спектру атак.

К счастью, при использовании NGINX можно реализовать несколько конфигураций для снижения подобных рисков.

Понимание отравления кэша посредством внедрения заголовка Host

Отравление кэша через внедрение заголовка Host — это сложная атака, при которой злоумышленник манипулирует кэшем веб-приложения, внедряя вредоносные данные в кэш через заголовок Host. Затем этот измененный кэш может предоставлять вредоносный контент законным пользователям. Смягчение этой атаки в NGINX включает обеспечение того, чтобы в ответах, которые кэшируются, использовались только допустимые Hostзаголовки, и любой запрос с подозрительным или измененным заголовком Host не отравлял кэш.

Пример использования curl для тестирования внедрения заголовка хоста

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

curl -v -H "Host: malicious.host" https://example.com/
  • -v включает подробный режим, который выводит подробную информацию о запросе и ответе, помогая в анализе.
  • -H "Host: malicious.host" устанавливает пользовательский заголовок Host для запроса. В оценке безопасности значение malicious.host будет заменено доменом или значением, контролируемым исследователем, или безвредным значением, предназначенным для целей тестирования.
  • https://example.com/ — это URL-адрес веб-сайта, владельцем которого вы являетесь.

Уязвимый сервер будет отвечать на такие запросы HTTP/1.1 200 OK, то есть он принимает произвольное значение заголовка Host. Это позволяет злоумышленнику отправлять неограниченное количество различных значений заголовков Host: в своих запросах, в конечном итоге увеличивая кэш-хранилище сервера до полного заполнения диска или вызывая раннюю очистку кэша, снижая производительность.

Правильным поведением было бы отклонять запросы, содержащие ненадежное значение заголовка Host.

Существует два разных подхода к защите сервера NGINX от уязвимостей внедрения заголовков Host.

Подход с внесением известных доменов в белый список

При таком подходе вы можете настроить NGINX для смягчения атак отравления кэша посредством внедрения заголовков Host, перечислив все домены по умолчанию на вашем сервере.

Что такое домены по умолчанию? Это любые ваши собственные домены, перечисленные в вашей конфигурации NGINX рядом с флагом default_server. Другими словами, вам нужно только добавить в белый список домены, которые обычно обслуживаются, когда заголовок Host вообще не предоставляется. Или, другими словами, когда ваш веб-сайт доступен напрямую по IP- адресу сервера. Это так называемые «основные» домены для вашего сервера.

Также лучше всего задать default_server в конфигурации NGINX:

Например:

listen 80 default_server;
listen 443 ssl default_server;
...
server {
    server_name www.example.com example.com ;
    ...
}

Вот основной веб-сайт example.com на вашем сервере. На вашем сервере может быть больше веб-сайтов, но они не могут быть назначены основными и не должны иметь установленный флаг default_server, так как он уникален для каждой комбинации прослушиваемого IP:порт.

Шаг 1: Определите доверенные хосты

Начните с определения набора основных/доверенных хостов для вашего приложения. В реальном сценарии это будут домены, которые ваше приложение должно обслуживать.

map $http_host $is_trusted {
    default   0;
    "www.example.com" 1;
    "example.com"  1;
}

Этот блок map сопоставляет доверенные заголовки Host с переменной $is_trusted, помечая их 1 как доверенные и 0 как все остальные.

Шаг 2: Блокировка или перенаправление ненадежных заголовков хоста

Используя эту переменную $is_trusted, мы можем настроить NGINX для блокировки или перенаправления запросов с недоверенными заголовками Host, предотвращая засорение кэша.

server {
    listen 80;
    server_name www.example.com example.com;

    if ($is_trusted = 0) {
        return 444; # No response to untrusted hosts
    }

    # Your usual server configuration
}

Предостережения

Хотя этот подход эффективно защищает ваш сервер от уязвимости заголовка Host, он требует явного добавления доменов в белый список вручную. Однако, если вы управляете конфигурацией NGINX с помощью инструментов конфигурации, таких как ansible, это становится не проблемой.

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

Подход с использованием универсального веб-сайта default_server

Блок сервера по умолчанию может перехватывать все остальные запросы, которые не соответствуют ни одному другому веб-сайту server_name. Это самый простой способ защититься от инъекции уязвимости заголовка Host в NGINX:

server {
    listen 80 default_server;
    return 444;
    server_name _;
}

Теперь любые запросы с произвольным (не указанным в другом месте) заголовком Host: будут достигать этого запрещающего блока server. Обязательно снимите флаг default_server с других веб-сайтов.

Предостережения

Этот подход, хотя и самый элегантный, не учитывает веб-клиентов, которые не поддерживают SNI. Когда такие клиенты действительно загружают ваш сайт через защищенное соединение, например, открывая «https://example.com/», NGINX не видит никаких заголовков Host, и из-за этого запрос попадет в блок сервера catch-all. И из-за этого клиенты, не поддерживающие SNI, не смогут загружать какие-либо сайты на вашем сервере.

Несмотря на широкую поддержку, все еще существуют области, в которых клиенты SNI сталкиваются с ограничениями или особыми требованиями:

  • Устаревшие системы и устройства IoT: некоторые старые системы или устройства IoT (Интернет вещей) могут не поддерживать SNI из-за устаревшего программного обеспечения или ограниченных возможностей. Это может повлиять на их способность подключаться к определенным службам, размещенным на общих серверах, требующих SNI для правильной маршрутизации.
  • Проблемы конфиденциальности с SNI: Традиционный SNI раскрывает имя хоста в открытом виде во время рукопожатия TLS, что может быть проблемой конфиденциальности. Зашифрованный SNI (ESNI) или его преемник, Encrypted Client Hello (ECH), решают эту проблему, шифруя часть рукопожатия, содержащую имя хоста. Однако темпы принятия и поддержки ESNI/ECH могут различаться, что влияет на конфиденциальность.
  • Сетевые и защитные устройства: некоторые промежуточные устройства (например, брандмауэры и балансировщики нагрузки) и старые защитные устройства могут иметь неполную или устаревшую поддержку SNI, что влияет на их способность правильно маршрутизировать или проверять трафик HTTPS. Это может потребовать обновлений или изменений конфигурации для обеспечения совместимости.

Рекомендации

Чтобы избежать непреднамеренной блокировки легитимных клиентов и при этом обеспечить защиту от атак с внедрением заголовков Host, рассмотрите возможность использования первого подхода, описанного в этой статье, соблюдая при этом передовые практики:

  • Настройте блоки сервера для всех известных, законных имен хостов, которые ваш сервер должен обслуживать. Это гарантирует, что любые клиенты, поддерживающие SNI, смогут установить соединение с желаемыми веб-сайтами
  • Настройте основной веб-сайт на вашем сервере, с флагом default_server рядом с его директивой listen. Это гарантирует, что любой клиент, который не поддерживает SNI, сможет получить доступ к основному веб-сайту
  • Если поддержка устаревших клиентов, не поддерживающих SNI, имеет решающее значение и вы хотите, чтобы для них работал не только основной веб-сайт, вам необходимо использовать несколько IP-адресов в конфигурации сервера и NGINX.

По этим причинам при настройке NGINX для устранения уязвимостей, включая внедрение заголовков хостов, крайне важно учитывать поведение клиентов, которые не поддерживают указание имени сервера (SNI).

Заключение

Хотя NGINX не устраняет инъекции заголовков Host напрямую из коробки, с помощью тщательной настройки и соблюдения передовых практик вы можете полностью защитить свои приложения от таких атак. Это критически важная часть поддержания уровня безопасности ваших веб-приложений, гарантирующая, что они реагируют только на легитимные и распознанные заголовки Host.

Written by Иван Васильков

Системный администратор и DevOps с опытом 10+ лет.