В чем разница между HTTP_HOST и SERVER_NAME в PHP?
Когда вы подумаете об использовании одного над другим и почему?
HTTP_HOST получается из заголовка HTTP-запроса, и именно это клиент фактически использовал в качестве «целевого хоста» запроса. SERVER_NAME определяется в конфигурации сервера. Какой из них зависит от того, для чего вам это нужно. Теперь вы должны понимать, что это контролируемое клиентом значение, которое, таким образом, не может быть надежным для использования в бизнес-логике, а другое является контролируемым сервером значением, которое является более надежным. Тем не менее, вам необходимо убедиться, что сервер веб-сервера имеет правильную конфигурацию SERVER_NAME . Взяв Apache HTTPD в качестве примера, вот выдержка из его документации :
Если имя ServerName не указано, сервер пытается вывести имя хоста, выполнив обратный поиск по IP-адресу. Если в ServerName не указан порт, сервер будет использовать порт из входящего запроса. Для обеспечения оптимальной надежности и предсказуемости вы должны указать явное имя хоста и порт, используя директиву ServerName .
Обновление : после проверки ответа Pekka на ваш вопрос, который содержит ссылку на ответ bobince, что PHP всегда будет возвращать значение SERVER_NAME для 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 в записи ServerName в httpd.conf (также проверьте предупреждение внизу документа !).
ServerName example.com UseCanonicalName on
Подводя итог, SERVER_NAME более надежен, но вы SERVER_NAME от конфигурации сервера!
HTTP_HOST – целевой хост, отправленный клиентом. Пользователь может свободно манипулировать пользователем. Это не проблема, чтобы отправить запрос на ваш сайт с запросом HTTP_HOST значение HTTP_HOST .
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://%/ # HTTP_HOST will work - Redirection to https://[::1]/ RewriteRule .* https://%/
Это применяется ТОЛЬКО, если вы получаете доступ к серверу без имени хоста.
если вы хотите проверить через server.php или что вы хотите назвать его следующим:
Затем обращайтесь к нему со всеми действительными URL-адресами для вашего сайта и проверьте разницу.
Зависит от того, что я хочу узнать. SERVER_NAME – это имя хоста сервера, а HTTP_HOST – это виртуальный хост, к которому подключен клиент.
Мне потребовалось некоторое время, чтобы понять, что люди подразумевают под « SERVER_NAME , более надежным ». Я использую общий сервер и не имею доступа к директивам виртуального хоста. Итак, я использую mod_rewrite в .htaccess для сопоставления различных HTTP_HOST s с разными каталогами. В этом случае это имеет HTTP_HOST .
Ситуация аналогична, если вы используете виртуальные хосты на основе имени: директива ServerName в виртуальном хосте просто говорит, какое имя хоста будет сопоставлено с этим виртуальным хостом. Суть в том, что в обоих случаях имя хоста, предоставленное клиентом во время запроса ( HTTP_HOST ), должно совпадать с именем на сервере, которое само отображается в каталог. Независимо от того, выполняется ли сопоставление с директивами виртуального хоста или с правилами htaccess mod_rewrite, здесь вторично. В этих случаях HTTP_HOST будет таким же, как SERVER_NAME . Я рад, что Apache настроен таким образом.
Однако ситуация отличается от виртуальных хостов на базе IP. В этом случае и только в этом случае SERVER_NAME и HTTP_HOST могут быть разными, потому что теперь клиент выбирает сервер по IP, а не по имени. Действительно, могут быть специальные конфигурации, где это важно.
Итак, начиная с этого SERVER_NAME , я буду использовать SERVER_NAME , на всякий случай мой код будет перенесен в эти специальные конфигурации.
Предполагая, что у вас есть простая настройка (CentOS 7, Apache 2.4.x и PHP 5.6.20) и только один веб-сайт (не предполагающий виртуальный хостинг) …
С точки $_SERVER[‘SERVER_NAME’] PHP, $_SERVER[‘SERVER_NAME’] – это элемент PHP, зарегистрированный в $_SERVER[‘SERVER_NAME’] $_SERVER на основе вашей конфигурации Apache ( **ServerName** с UseCanonicalName On ) в httpd.conf (будь то из включенного виртуального хоста файл конфигурации, что угодно и т. д.). HTTP_HOST получен из заголовка host HTTP. Рассматривайте это как пользовательский ввод. Фильтрация и проверка перед использованием.
Вот пример того, где я использую $_SERVER[‘SERVER_NAME’] в качестве основы для сравнения. Следующий метод относится к конкретному дочернему классу, который я сделал с именем ServerValidator (дочерний 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’] .
Теперь я использую superglobal, чтобы объяснить мой пример, но это только потому, что некоторые люди не знакомы с INPUT_GET , INPUT_POST и INPUT_SERVER в отношении filter_input_array() .
Суть в том, что я не обрабатываю запросы POST на моем сервере, если не выполняются все четыре условия. Следовательно, с точки зрения запросов POST отказ предоставить HTTP- host заголовок (присутствие проверен для более ранних) вызывает заклинания для строгих браузеров HTTP 1.0 . Кроме того, запрашиваемый хост должен соответствовать значению для ServerName в httpd.conf , а по расширению – значение $_SERVER(‘SERVER_NAME’) в $_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).
Поскольку balusC сказал, что SERVER_NAME не является надежным и может быть изменен в конфигурации apache, конфигурации сервера сервера и брандмауэра, которые могут находиться между вами и сервером.
Следующая функция всегда возвращает реальный хост (пользовательский типизированный хост) без порта, и он почти надежен:
В чем разница между HTTP_HOST и SERVER_NAME в PHP?
«Обычно я использую HTTP_HOST, чтобы пользователь оставался на том же имени хоста, с которого он начал. Например, если у меня один и тот же сайт в домене .com и .org, я не хочу отправлять кого-то из .org в .com, особенно если у них могут быть токены входа в систему .org, которые они потеряют, если отправят на другой домен. » — Это и некоторые другие интересные моменты от stackoverflow.com/questions/1459739/…
@ Yarin, не забудьте белый список — проверьте результаты HTTP_HOST . В противном случае злоумышленник может ввести любое значение в HTTP-запросе Host: и заставить сервер принять его.
Начинающие. Этот вопрос относится к значениям, обычно получаемым через $_SERVER[‘HTTP_HOST’] или $_SERVER[‘SERVER_NAME’]
9 ответов
HTTP_HOST получен из заголовка HTTP-запроса, и именно это клиент фактически использовал как «целевой хост» запроса. SERVER_NAME определяется в конфигурации сервера. Какой из них зависит от того, для чего вам это нужно. Теперь вы должны понимать, что это контролируемое клиентом значение, которое, таким образом, не может быть надежным для использования в бизнес-логике, а другое является контролируемым сервером значением, которое является более надежным. Тем не менее вам необходимо убедиться, что веб-сервер имеет правильную конфигурацию SERVER_NAME . Взяв Apache HTTPD в качестве примера, здесь выдержка из ее документации:
Если не указано ServerName , тогда сервер пытается вывести имя хоста, выполнив обратный поиск по IP-адресу. Если ни один порт не указан в ServerName , тогда сервер будет использовать порт из входящего запроса. Для обеспечения оптимальной надежности и предсказуемости вы должны указать явное имя хоста и порт с помощью директивы ServerName .
Обновить: после проверки ответа Pekka на ваш вопрос, который содержит ссылку на bobince answer, что 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 в записи ServerName в httpd.conf (также проверьте предупреждение внизу документ!).
ServerName example.com UseCanonicalName on
Обобщенный, SERVER_NAME более надежный, но вы зависимый в конфигурации сервера!