В чем разница между хостом HTTP и именем сервера в PHP?


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

9 485

9 ответов:

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

, если не ServerName указывается, затем сервер пытается вывести имя хоста, выполнив обратный поиск по IP-адресу. Если порт не указан в ServerName, то сервер будет использовать порт из входящего запроса. Для оптимальной надежности и предсказуемости необходимо указать явное имя хоста и порт используя bobince это что PHP всегда будет возвращать HTTP_HOST ' s значение для 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 port-based virtualhosts)

отметим, что 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}/

это применимо только при доступе к серверу без имени хоста.

Если вы хотите проверить через сервер.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 superglobal на основе конфигурации Apache (. Рассматривайте это как пользователя вход. Фильтруйте и проверяйте перед использованием.

вот пример, где я использую $_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 заголовок (наличие проверено на более ранние) заклинания doom строго HTTP 1.0 - браузеры. Более того, запрошенный хост должно соответствовать значению на ServerName на httpd.conf, и, по расширению, значение для $_SERVER('SERVER_NAME') на $_SERVER суперглобальная. Опять Же, Я будет использовать INPUT_SERVER с функциями фильтра PHP, но вы ловите мой дрейф.

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

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

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

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

function getRealHost(){
   list($realHost,)=explode(':',$_SERVER['HTTP_HOST']);
   return $realHost;
}