В чем разница между HTTP-ХОСТОМ и ИМЕНЕМ СЕРВЕРА в PHP?


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

Author: slick, 2010-02-19

9 answers

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 более надежен, но вы зависите от конфигурации сервера!

 730
Author: BalusC, 2017-05-23 11:33:26

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

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

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

 60
Author: Pekka 웃, 2017-05-23 11:47:36

Как я уже упоминал в этом ответе , если сервер работает на порту, отличном от 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'
 45
Author: Simon East, 2017-05-23 12:26:42

Пожалуйста, обратите внимание, что если вы хотите использовать 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}/

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

 25
Author: Daniel Marschall, 2015-08-11 00:23:01

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

<?php

phpinfo(INFO_VARIABLES);

?>

Или

<?php

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

print_r($_SERVER);

?>

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

 5
Author: stevewh, 2011-09-03 10:17:15

Зависит от того, что я хочу выяснить. ИМЯ_СЕРВЕРА - это имя хоста сервера, в то время как HTTP_HOST - это виртуальный хост, к которому подключен клиент.

 4
Author: Rowland Shaw, 2010-02-19 15:31:32

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

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

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

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

 2
Author: Dominic108, 2015-08-11 00:31:18

Предполагая, что у вас простая настройка (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'] (в конечном счете полученное из запрошенного заголовка HTTP host) совпадает $_SERVER['SERVER_NAME'].

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

Суть в том, что я не обрабатываю запросы POST на своем сервере, если не выполнены все четыре условия. Следовательно, с точки зрения ДОЛЖНОСТИ запросы, неспособность предоставить заголовок HTTP host (наличие проверено на более ранние) заклинания doom для строгих браузеров 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).

 2
Author: Anthony Rutledge, 2017-03-09 15:41:10

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

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

function getRealHost(){
   list($realHost,)=explode(':',$_SERVER['HTTP_HOST']);
   return $realHost;
}
 0
Author: MSS, 2016-05-20 13:21:26