Вопрос или проблема
У меня есть сервер Apache/2.4.6 (CentOS) с несколькими поддоменами в качестве ServerAlias в Apache VirtualHost.
что-то вроде:
<VirtualHost *:443>
ServerName mydomain.com
ServerAlias a.mydomain.com
ServerAlias b.mydomain.com
Каждая клиентская компания должна получать доступ через свой поддомен, и для каждой клиентской компании существуют разные базы данных для безопасности, обеспечивающая изоляцию данных.
Меня предупредил эксперт по кибербезопасности о том, что существует уязвимость, при которой пользователь одного поддомена ‘a.mydomain.com’ может получить доступ к другому поддомену ‘b.mydomain.com’, добавив заголовок Host в запросы клиента к веб-серверу.
Сначала я пытался получить информацию в PHP, но не смог, так как PHP не получает информацию о заголовках. Затем я переключился на поиск решения этой ситуации на уровне веб-сервера – Apache.
Я хочу обнаружить и отклонить, когда мошеннический пользователь пытается обмануть сервер и отправить запрос на другой поддомен, используя заголовок Host, в этом примере пользователь должен обслуживаться a.mydomain.com, а не b.mydomain.com:
curl 'https://a.mydomain.com/users/login' \
-H 'Host: b.mydomain.com' \
--data-raw $'{"email":"[email protected]","password":"*****"}'
Обычный вызов с клиентской стороны выглядит так:
curl 'https://a.mydomain.com/users/login' \
--data-raw $'{"email":"[email protected]","password":"*****"}'
Я пытался использовать RequestHeader unset host
, но это не сработало, как я ожидал.
Мое ожидание было таким, что если мошеннический пользователь отправляет заголовок “Host”, сервер должен игнорировать его. Это привело бы к тому, что оба вызова curl выше были бы фактически одинаковыми.
Я думаю, что происходит следующее: Apache использует URL в вызове, но если есть заголовок “Host”, он имеет преимущество, и это то, что используется, а оригинальный домен из URL отбрасывается.
Если это так, то RequestHeader unset host
не отправляет никакой host в мой код PHP, что приводит к сбою моего кода, так как ему нужно знать, какая клиентская компания вызывает его.
Это не имеет смысла, так как заголовок Host
– это то, как Apache изначально знает URL.
Обычные HTTP-запросы не предоставляют буквальный URL веб-серверу. Если вы запустите curl с опцией -v
, вы увидите, что запрос выглядит как GET /users/login
, т.е. присутствует только путь (и строка запроса) – это не GET https://a.mydomain.com/users/login
, как вы, вероятно, предполагаете.
Так куда уходит часть имени хоста URL, когда выполняется HTTP-запрос? Единственное место, куда она уходит, с точки зрения HTTP, – это заголовок Host:
. Поэтому невозможно, чтобы заголовок был “другим, чем URL запроса”, потому что это и есть URL запроса.
Другими словами, изменение заголовка Host не является действительно “обманом сервера” больше, чем просто изменение URL; просто сделав https://b.mydomain.com/users/login
, вы получите такой же эффект.
Может быть, есть какая-то другая проблема, о которой “эксперт” пытался вас предупредить (например, возможно, они говорили о запросе, который пытается отправить два заголовка Host, от чего, как я считаю, уже защищены как Apache, так и PHP; или, возможно, они имели в виду, что сервер принимает несоответствующие TLS SNI и HTTP Host, что также не является большой проблемой само по себе), но вам нужно будет спросить их для уточнения.
Мой дикий guess заключается в том, что ваше приложение не изолирует сессии PHP по доменам, так что если пользователь входит в систему и получает cookie сессии для домена A, но затем пытается отправить его для домена B, приложение принимает его как действительную аутентификацию для домена B. Это было бы реальной проблемой безопасности, но не связано с подделкой заголовка Host как такового.
Ответ или решение
Вопрос об отклонении заголовка Host, если он отличается от URL запроса в Apache, требует внимательного подхода, особенно когда речь идет о безопасности при использовании поддоменов. Давайте разберем этот вопрос и предложим несколько решений.
Проблема
У вас есть сервер Apache версии 2.4.6, который обслуживает несколько поддоменов с помощью директивы ServerAlias
. Правильная конфигурация необходима, чтобы избежать ситуации, когда потенциальный злоумышленник может подменить заголовок Host, что может привести к доступу к данным другой компании.
Объяснение
Как верно отмечается, заголовок Host является важной частью HTTP-запроса. Он используется веб-сервером для определения, какой виртуальный хост (или поддомен) должен обработать данный запрос. Таким образом, фактически изменение заголовка Host может быть эквивалентно прямому обращению к другому поддомену.
Защита на уровне Apache
Чтобы предотвратить возможные атаки через заголовок Host, вы можете использовать следующие механизмы конфигурации в Apache:
-
Ограничение в зависимости от заголовка Host:
Используйте директивуRewriteCond
иRewriteRule
для проверки и отклонения запросов с неверным заголовком Host. Это можно сделать следующим образом:<VirtualHost *:443> ServerName mydomain.com ServerAlias a.mydomain.com ServerAlias b.mydomain.com RewriteEngine On # Отклонить запросы с неправильным Host заголовком RewriteCond %{HTTP_HOST} !^a\.mydomain\.com$ [NC] RewriteRule ^ - [F] # Ваша основная конфигурация DocumentRoot /path/to/your/site # Другие настройки </VirtualHost>
В данном случае, если Host заголовок не соответствует поддомену
a.mydomain.com
, запрос будет отклонен с ошибкой 403. -
Проверка на уровне приложения:
Помните, что ограничения на уровне веб-сервера могут быть недостаточными. Ваше приложение (например, на PHP) также должно проверять, соответствует ли запрашиваемый поддомен ожиданиям. Это поможет защитить даже в случае, если кто-то сможет обойти настройки Apache.Пример кода проверки в PHP:
$allowedHost = 'a.mydomain.com'; if ($_SERVER['HTTP_HOST'] !== $allowedHost) { header("HTTP/1.0 403 Forbidden"); exit('Access denied'); }
Итого
Применив указанные выше настройки, вы сможете существенно повысить безопасность своих приложений и предотвратить возможность манипуляции заголовком Host.
Также учтите, что важно следовать лучшим практикам по безопасности и регулярно обновлять серверное ПО для защиты от новых уязвимостей. Помните, что никакое решение не может гарантировать абсолютную безопасность, поэтому постоянный мониторинг и анализ логов – важная часть вашей защиты.