Вопрос

Когда бы вы подумали об использовании одного поверх другого и почему?

Это было полезно?

Решение

В HTTP_HOST получается из Заголовок HTTP - запроса и это то, что клиент фактически использовал в качестве "целевого хоста" запроса.В SERVER_NAME определяется в конфигурации сервера.Какой из них использовать, зависит от того, для чего он вам нужен.Однако теперь вы должны понимать, что первое - это контролируемое клиентом значение, которое, таким образом, может быть ненадежным для использования в бизнес-логике, а другое - контролируемое сервером значение, которое является более надежным.Однако вам необходимо убедиться, что рассматриваемый веб-сервер имеет SERVER_NAME правильно настроенный.Взяв Apache HTTPD в качестве примера, вот выдержка из его документация:

Если нет ServerName указывается, затем сервер пытается определить имя хоста, выполняя обратный поиск по IP-адресу.Если порт не указан в ServerName, тогда сервер будет использовать порт из входящего запроса.Для оптимальной надежности и предсказуемости вам следует указать явное имя хоста и порт, используя ServerName директива.


Обновить:после проверки ответ Пекки на ваш вопрос который содержит ссылку на ответ бобинса что PHP всегда будет возвращать HTTP_HOSTзначение для SERVER_NAME, что противоречит моему собственному опыту работы с PHP 4.x + Apache HTTPD 1.2.x пару лет назад я сдул немного пыли с моей текущей среды XAMPP в Windows XP (Apache HTTPD 2.2.1 с PHP 5.2.8), запустил ее, создал страницу PHP, которая печатает оба значения, создал тестовое приложение Java с использованием URLConnection чтобы изменить Host заголовок и тесты научили меня, что это действительно (неправильно) так.

После первого подозрения в PHP и копания в некоторых Отчеты об ошибках PHP что касается темы, я узнал, что корень проблемы кроется в используемом веб-сервере, что он неправильно вернул HTTP Host заголовок , когда SERVER_NAME был запрошен.Поэтому я углубился в Отчеты об ошибках Apache HTTPD используя различные ключевые слова что касается предмета, и я, наконец, нашел связанная ошибка.Такое поведение было введено примерно с Apache HTTPD 1.3.Вам нужно установить UseCanonicalName директива для on в <VirtualHost> вступление в ServerName в httpd.conf (также проверьте предупреждение в нижней части документ!).

<VirtualHost *>
    ServerName example.com
    UseCanonicalName on
</VirtualHost> 

У меня это сработало.

Обобщенный, SERVER_NAME это более надежно, но вы зависимый в конфигурации сервера!

Другие советы

HTTP_HOST является целевым хостом, отправленным клиентом.Пользователь может свободно манипулировать им.Нет проблем отправить запрос на ваш сайт с просьбой HTTP_HOST значение www.stackoverflow.com.

SERVER_NAME поступает с сервера VirtualHost определение и поэтому считается более надежным.Однако им также можно управлять извне при определенных условиях, связанных с настройкой вашего веб-сервера:Видишь это Это ТАКОЙ вопрос это касается аспектов безопасности обеих вариаций.

Вы не должны полагаться ни на то, ни на другое, чтобы быть в безопасности.Тем не менее, то, что использовать, действительно зависит от того, что вы хотите сделать.Если вы хотите определить, в каком домене запущен ваш скрипт, вы можете безопасно использовать HTTP_HOST пока недопустимые значения, исходящие от злоумышленника, ничего не могут нарушить.

Как я уже упоминал в этот ответ, если сервер работает на порту, отличном от 80 (что может быть обычным на компьютере для разработки / интрасети), то HTTP_HOST содержит порт, в то время как SERVER_NAME не делает этого.

$_SERVER['HTTP_HOST'] == 'localhost:8080'
$_SERVER['SERVER_NAME'] == 'localhost'

(По крайней мере, это то, что я заметил в виртуальных хостингах на основе портов Apache)

Обратите внимание , что HTTP_HOST делает не содержать :443 при запуске по протоколу HTTPS (если только вы не используете нестандартный порт, который я не тестировал).

Как отмечали другие, эти два параметра также отличаются при использовании IPv6:

$_SERVER['HTTP_HOST'] == '[::1]'
$_SERVER['SERVER_NAME'] == '::1'

Пожалуйста, обратите внимание, что если вы хотите использовать IPv6, вы, вероятно, захотите использовать HTTP_HOST вместо того , чтобы SERVER_NAME .Если вы войдете http://[::1]/ переменными среды будут следующие:

HTTP_HOST = [::1]
SERVER_NAME = ::1

Это означает, что если вы выполните mod_rewrite, например, вы можете получить неприятный результат.Пример для перенаправления SSL:

# SERVER_NAME will NOT work - Redirection to https://::1/
RewriteRule .* https://%{SERVER_NAME}/

# HTTP_HOST will work - Redirection to https://[::1]/
RewriteRule .* https://%{HTTP_HOST}/

Это применимо ТОЛЬКО в том случае, если вы обращаетесь к серверу без имени хоста.

если вы хотите проверить через server.php или как бы вы ни хотели это назвать, используя следующее:

<?php

phpinfo(INFO_VARIABLES);

?>

или

<?php

header("Content-type: text/plain");

print_r($_SERVER);

?>

Затем откройте его со всеми допустимыми URL-адресами для вашего сайта и проверьте разницу.

Зависит от того, что я хочу выяснить.SERVER_NAME - это имя хоста сервера, в то время как HTTP_HOST - это виртуальный хост, к которому подключен клиент.

Мне потребовалось некоторое время , чтобы понять , что люди имели в виду под 'SERVER_NAME это более надежно".Я использую общий сервер и не имею доступа к директивам виртуального хоста.Итак, я использую mod_rewrite в .htaccess для отображения различных HTTP_HOSTs в разные каталоги.В таком случае, это HTTP_HOST это имеет смысл.

Аналогичная ситуация возникает, если использовать виртуальные хосты на основе имен:в ServerName директива внутри виртуального хоста просто указывает, какое имя хоста будет сопоставлено этому виртуальному хосту.Суть в том, что в обоих случаях имя хоста, предоставленное клиентом во время запроса (HTTP_HOST), должно быть сопоставлено с именем на сервере, которое само сопоставляется каталогу.Выполняется ли сопоставление с помощью директив виртуального хоста или с помощью правил htaccess mod_rewrite, здесь второстепенно.В этих случаях, HTTP_HOST будет таким же , как SERVER_NAME.Я рад, что Apache настроен таким образом.

Однако с виртуальными хостами на основе IP ситуация иная.В этом случае и только в этом случае, SERVER_NAME и HTTP_HOST может быть по-другому, потому что теперь клиент выбирает сервер по IP, а не по имени. Действительно, могут существовать особые конфигурации, где это важно.

Итак, начиная с этого момента, я буду использовать SERVER_NAME, на всякий случай, если мой код перенесен в эти специальные конфигурации.

Предполагая, что у вас простая настройка (CentOS 7, Apache 2.4.x и PHP 5.6.20) и только один веб-сайт (не предполагающий виртуального хостинга)...

В смысле PHP, $_SERVER['SERVER_NAME'] является элементом, который PHP регистрирует в $_SERVER суперглобальный на основе вашей конфигурации Apache (**ServerName** директива с UseCanonicalName On ) в httpd.conf (будь то из включенного файла конфигурации виртуального хоста, что угодно и т.д. ). HTTP_HOST является производным от HTTP host заголовок.Рассматривайте это как пользовательский ввод.Отфильтруйте и проверьте перед использованием.

Вот пример того, где я использую $_SERVER['SERVER_NAME'] в качестве основы для сравнения.Следующий метод взят из конкретного дочернего класса, который я создал с именем ServerValidator (дитя Validator). ServerValidator проверяет шесть или семь элементов в $_SERVER перед их использованием.

При определении того, является ли HTTP-запрос POST, я использую этот метод.

public function isPOST()
{
    return (($this->requestMethod === 'POST')    &&  // Ignore
            $this->hasTokenTimeLeft()            &&  // Ignore
            $this->hasSameGETandPOSTIdentities() &&  // Ingore
            ($this->httpHost === filter_input(INPUT_SERVER, 'SERVER_NAME')));
}

К моменту вызова этого метода вся фильтрация и проверка соответствующих элементов $_SERVER были бы выполнены (и соответствующие свойства установлены).

Линия ...

($this->httpHost === filter_input(INPUT_SERVER, 'SERVER_NAME')

...проверяет, что $_SERVER['HTTP_HOST'] значение (в конечном счете, полученное из запрошенного host HTTP заголовок) соответствует $_SERVER['SERVER_NAME'].

Теперь я использую superglobal speak для объяснения моего примера, но это только потому, что некоторые люди не знакомы с INPUT_GET, INPUT_POST, и INPUT_SERVER в отношении filter_input_array().

Суть в том, что я не обрабатываю POST-запросы на своем сервере, если только ВСЕ соблюдены четыре условия.Следовательно, с точки зрения POST-запросов, неспособность предоставить HTTP host заклинания заголовка (присутствие проверено для предыдущих) гибель для строгих HTTP 1.0 браузеры.Более того, запрошенный хост должно соответствовать значению для ServerName в httpd.conf, и, путем расширения, значение для $_SERVER('SERVER_NAME') в $_SERVER суперглобальный.Опять же, я бы использовал INPUT_SERVER с функциями фильтрации PHP, но вы уловили мой намек.

Имейте в виду, что Apache часто использует ServerName в стандартные перенаправления (например, оставить косую черту в конце URL-адреса:Пример, http://www.foo.com становление http://www.foo.com/), даже если вы не используете перезапись URL-адреса.

Я использую $_SERVER['SERVER_NAME'] как стандарт, не $_SERVER['HTTP_HOST'].По этому вопросу много говорят взад и вперед. $_SERVER['HTTP_HOST'] может быть пустым, поэтому это не должно быть основой для создания соглашений о коде, таких как мой открытый метод выше.Но только потому, что оба параметра могут быть установлены, не гарантирует, что они будут равны.Тестирование - лучший способ узнать наверняка (принимая во внимание версию Apache и версию PHP).

Как сказал балусК, ИМЯ_СЕРВЕРА ненадежно и может быть изменено в конфигурации apache, конфигурации имени сервера сервера и брандмауэра, который может быть между вами и сервером.

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

function getRealHost(){
   list($realHost,)=explode(':',$_SERVER['HTTP_HOST']);
   return $realHost;
}
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top