В чём разница между HTTP_HOST и SERVER_NAME в PHP? Правильное использование
'; ?> ``` На локальном сервере (OpenServer) оба показывают `localhost`. Но когда я залил сайт на хостинг, то заметил, что при обращении через IP-адрес `HTTP_HOST` показывает IP, а `SERVER_NAME` — доменное имя. А ещё я слышал, что `HTTP_HOST` может быть подделан через заголовки HTTP-запроса, и это создаёт уязвимость. Подскажите, пожалуйста: 1. В чём принципиальная разница между этими переменными? 2. Какую из них безопаснее использовать для редиректов, генерации ссылок и проверки домена? 3. Есть ли случаи, когда они могут кардинально отличаться? Буду благодарен за подробное объяснение с примерами! Я хочу понять не просто "как работает", а "почему так сделано" и какой вариант правильнее в разных ситуациях. <<
Ключевое различие: источник данных
Главное отличие кроется в том, откуда берётся каждое значение:
- HTTP_HOST — берётся из HTTP-заголовка
Host, который клиент (браузер, curl, бот) отправляет в запросе. Это значение может быть любым — клиент сам решает, что отправить. - SERVER_NAME — задаётся конфигурацией веб-сервера (Apache/Nginx). Обычно это значение из директивы
ServerNameв Apache илиserver_nameв Nginx.
Когда они совпадают?
В 95% случаев для обычного сайта, когда пользователь заходит по домену example.com, оба значения будут одинаковыми. Но есть важные исключения:
Сценарии расхождения
1. Обращение по IP-адресу
// Запрос: http://192.168.1.1/site.php
$_SERVER['HTTP_HOST'] = '192.168.1.1'; // то, что ввел пользователь
$_SERVER['SERVER_NAME'] = 'example.com'; // то, что настроено в сервере
2. Виртуальные хосты (VirtualHost)
// Apache config:
<VirtualHost *:80>
ServerName site1.com
ServerAlias site2.com
</VirtualHost>
// Запрос к site2.com:
$_SERVER['HTTP_HOST'] = 'site2.com'; // из заголовка
$_SERVER['SERVER_NAME'] = 'site1.com'; // из ServerName (основной)
3. Подмена заголовка (HTTP Host header attack)
// Злоумышленник отправляет:
curl -H "Host: evil.com" http://example.com/
$_SERVER['HTTP_HOST'] = 'evil.com'; // подделано!
$_SERVER['SERVER_NAME'] = 'example.com'; // настоящий домен
Какую переменную использовать?
Для редиректов и генерации абсолютных ссылок — HTTP_HOST
// Правильно:
$url = 'https://' . $_SERVER['HTTP_HOST'] . '/page';
header("Location: $url");
// Потому что пользователь видит именно этот домен в адресной строке
Для проверки легитимности домена — SERVER_NAME
// Безопасная проверка:
$allowed_domains = ['example.com', 'example.org'];
if (!in_array($_SERVER['SERVER_NAME'], $allowed_domains)) {
die('Доступ запрещён');
}
// HTTP_HOST здесь использовать опасно!
Практические рекомендации
- Для вывода на экран — используйте
HTTP_HOST. Пользователь должен видеть именно тот адрес, который он ввёл. - Для аутентификации и критичных проверок — используйте
SERVER_NAME. Он надёжнее, так как не подделывается. - В CMS и фреймворках часто используют
HTTP_HOSTдля определения текущего домена, но с дополнительной валидацией через белый список. - В конфигурации веб-сервера всегда явно указывайте
ServerName— это повышает безопасность.
Пример правильной обработки
function getCurrentDomain() {
// Проверяем, что HTTP_HOST не подделан
if (isset($_SERVER['HTTP_HOST'])) {
$host = $_SERVER['HTTP_HOST'];
// Очищаем от потенциально опасных символов
$host = strtolower(trim($host));
$host = filter_var($host, FILTER_SANITIZE_URL);
return $host;
}
return $_SERVER['SERVER_NAME'];
}
// Использование:
$domain = getCurrentDomain();
$url = "https://{$domain}/dashboard";
Итог: HTTP_HOST — это то, что хочет показать пользователь, SERVER_NAME — то, что настроил администратор. Для публичного контента используйте HTTP_HOST, для безопасности — SERVER_NAME.
Дополнение: особенности в разных веб-серверах
Стоит отметить, что поведение SERVER_NAME может различаться в зависимости от настроек веб-сервера:
- Apache с UseCanonicalName On (по умолчанию) —
SERVER_NAMEравен значению из директивыServerName. Поведение предсказуемое. - Apache с UseCanonicalName Off —
SERVER_NAMEможет совпадать сHTTP_HOST, то есть браться из заголовка запроса. Это снижает безопасность. - Nginx —
SERVER_NAMEвсегда равен значению из конфигурацииserver_name, если не используется проксирование.
Прокси и балансировщики
Если сайт стоит за обратным прокси (например, Cloudflare, nginx как прокси для Apache), то ситуация усложняется:
// Клиент -> Cloudflare -> Ваш сервер
$_SERVER['HTTP_HOST'] = 'example.com'; // оригинальный домен
$_SERVER['SERVER_NAME'] = '127.0.0.1'; // внутренний IP сервера!
В таких случаях нужно смотреть на заголовок X-Forwarded-Host:
// Правильно за прокси:
$host = $_SERVER['HTTP_X_FORWARDED_HOST'] ?? $_SERVER['HTTP_HOST'];
Совет: всегда проверяйте, как ваша инфраструктура обрабатывает эти переменные. Для продакшена лучше явно задавать домен в конфигурационном файле приложения, а не полагаться на серверные переменные.
Ответов пока нет.
Войдите чтобы оставить ответ