Intereting Posts
Класс существует во внешнем файле Любое обходное решение для использования PHP SoapClient с локальным файлом WSDL (NON-URI)? PHP получает разницу между двумя массивами объектов Включение / установка расширения Curl (OSX Server / PHP 5.3.3 / Apache 2.2) Как заказывать сообщения WordPress по пользовательской дате поля? Загрузить форму несколько раз в php В PHP / MySQL следует открыть несколько соединений с базой данных или поделиться 1? Создать страницу, на которой отображаются файлы журнала Codeigniter на веб-странице. написать форму в базу данных с помощью jquery Как отобразить эту строку HTML в функции echo php Простой PHP-редактор текстовых файлов Как определить, какие файлы PHP фактически используются, а какие нет? Как загрузить css в codeigniter Как получить 2 или 3 средней точки радиального местоположения (широта, долгота) PHP – Как объединить массивы в один массив во время цикла?

PHP $ _SERVER vs. $ _SERVER , правильно ли я понимаю страницы man?

Я много искал, а также читал документы PHP $ _SERVER . Имею ли я это право относительно того, что использовать для моих PHP-скриптов для простых определений ссылок, используемых на моем сайте?

$_SERVER['SERVER_NAME'] основан на файле конфигурации вашего веб-сервера (Apache2 в моем случае) и варьируется в зависимости от нескольких директив: (1) VirtualHost, (2) ServerName, (3) UseCanonicalName и т. Д.

$_SERVER['HTTP_HOST'] основан на запросе клиента.

Поэтому мне показалось, что правильный, чтобы использовать мои сценарии как можно более совместимые, будет $_SERVER['HTTP_HOST'] . Правильно ли это предположение?

Последующие комментарии:

Наверное, после прочтения этой статьи я получил немного параноиков и заметил, что некоторые люди сказали: «Они не будут доверять никаким из $_SERVER vars»:

  • http://markjaquith.wordpress.com/2009/09/21/php-server-vars-not-safe-in-forms-or-links/

  • http://php.net/manual/en/reserved.variables.server.php#89567 (комментарий: Vladimir Kornea 14-Mar-2009 01:06)

По-видимому, обсуждение в основном связано с $_SERVER['PHP_SELF'] и почему вы не должны использовать его в атрибуте action формы без надлежащего экранирования для предотвращения атак XSS.

Мой вывод о моем первоначальном вопросе выше заключается в том, что «безопасно» использовать $_SERVER['HTTP_HOST'] для всех ссылок на сайте, не беспокоясь о атак XSS, даже если они используются в формах.

Пожалуйста, поправьте меня, если я ошибаюсь.

Это, наверное, первая мысль. Но это немного сложнее. См. Статью Криса Шифлетта SERVER_NAME сравнении с HTTP_HOST .

Кажется, что нет серебряной пули. Только когда вы заставляете Apache использовать каноническое имя, вы всегда получите правильное имя сервера с SERVER_NAME .

Таким образом, вы либо идете с этим, либо проверяете имя хоста на белый список:

 $allowed_hosts = array('foo.example.com', 'bar.example.com'); if (!isset($_SERVER['HTTP_HOST']) || !in_array($_SERVER['HTTP_HOST'], $allowed_hosts)) { header($_SERVER['SERVER_PROTOCOL'].' 400 Bad Request'); exit; } 

Еще одно примечание: если сервер работает на порту, отличном от 80 (как это может быть распространено на машине разработки / интрасети), то HTTP_HOST содержит порт, а SERVER_NAME – нет.

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

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

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

Это подробный перевод того, что Symfony использует для получения имени хоста ( см. Второй пример для более буквального перевода ):

 function getHost() { $possibleHostSources = array('HTTP_X_FORWARDED_HOST', 'HTTP_HOST', 'SERVER_NAME', 'SERVER_ADDR'); $sourceTransformations = array( "HTTP_X_FORWARDED_HOST" => function($value) { $elements = explode(',', $value); return trim(end($elements)); } ); $host = ''; foreach ($possibleHostSources as $source) { if (!empty($host)) break; if (empty($_SERVER[$source])) continue; $host = $_SERVER[$source]; if (array_key_exists($source, $sourceTransformations)) { $host = $sourceTransformations[$source]($host); } } // Remove port number from host $host = preg_replace('/:\d+$/', '', $host); return trim($host); } 

Устаревшие:

Это мой перевод на простой PHP метода, используемого в структуре Symfony, который пытается получить имя хоста всеми возможными способами в порядке наилучшей практики:

 function get_host() { if ($host = $_SERVER['HTTP_X_FORWARDED_HOST']) { $elements = explode(',', $host); $host = trim(end($elements)); } else { if (!$host = $_SERVER['HTTP_HOST']) { if (!$host = $_SERVER['SERVER_NAME']) { $host = !empty($_SERVER['SERVER_ADDR']) ? $_SERVER['SERVER_ADDR'] : ''; } } } // Remove port number from host $host = preg_replace('/:\d+$/', '', $host); return trim($host); } 

Используйте также. Они оба одинаково безопасны, так как во многих случаях SERVER_NAME просто заполняется из HTTP_HOST. Обычно я запускаю HTTP_HOST, так что пользователь остается на том точном имени хоста, с которого они начали. Например, если у меня есть тот же сайт в домене .com и .org, я не хочу отправлять кого-то из .org в .com, особенно если у них могут быть маркеры входа в .org, которые они потеряли бы, если бы отправили другой домен.

В любом случае, вам просто нужно быть уверенным, что ваш webapp будет реагировать только на хорошо известные домены. Это может быть выполнено либо (a) с проверкой на стороне приложения, как Gumbo, либо (b) с использованием виртуального хоста для имени домена, которое вы хотите, которое не отвечает на запросы, которые дают неизвестный заголовок Host.

Причина этого в том, что если вы разрешаете доступ к вашему сайту под каким-либо старым именем, вы можете открыться для DNS-повторных атак (где имя хоста другого сайта указывает на ваш IP-адрес, пользователь обращается к вашему сайту с именем хоста злоумышленника, затем имя хоста переносится на IP-адрес злоумышленника, беря с собой файлы cookie / auth) и угон поисковой системы (где злоумышленник указывает свое собственное имя хоста на вашем сайте и пытается заставить поисковые системы рассматривать его как «лучшее» первичное имя хоста).

По-видимому, обсуждение в основном связано с $ _SERVER ['PHP_SELF'] и почему вы не должны использовать его в атрибуте action формы без надлежащего экранирования для предотвращения атак XSS.

Пфф. Ну, вы не должны использовать ничего в каком-либо атрибуте без экранирования с htmlspecialchars($string, ENT_QUOTES) , поэтому нет ничего особенного в переменных сервера.

Основное различие между ними состоит в том, что $_SERVER['SERVER_NAME'] является управляемой сервером переменной, а $_SERVER['HTTP_HOST'] является контролируемым пользователем значением.

Эмпирическое правило – никогда не доверять значениям пользователя, поэтому $_SERVER['SERVER_NAME'] – лучший выбор.

Как указал Gumbo, Apache построит SERVER_NAME из пользовательских значений, если вы не установите UseCanonicalName On .

Изменить: Сказав все это, если сайт использует виртуальный хост на основе имени, заголовок HTTP-хоста является единственным способом достижения сайтов, которые не являются сайтом по умолчанию.

Безопасно ли использовать $_SERVER['HTTP_HOST'] для всех ссылок на сайте, не беспокоясь о атак XSS, даже если они используются в формах?

Да, безопасно использовать $_SERVER['HTTP_HOST'] , (и даже $_GET и $_POST ), пока вы их проверяете, прежде чем принимать их. Это то, что я делаю для безопасных производственных серверов:

 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ $reject_request = true; if(array_key_exists('HTTP_HOST', $_SERVER)){ $host_name = $_SERVER['HTTP_HOST']; // [ need to cater for `host:port` since some "buggy" SAPI(s) have been known to return the port too, see http://goo.gl/bFrbCO $strpos = strpos($host_name, ':'); if($strpos !== false){ $host_name = substr($host_name, $strpos); } // ] // [ for dynamic verification, replace this chunk with db/file/curl queries $reject_request = !array_key_exists($host_name, array( 'a.com' => null, 'aacom' => null, 'b.com' => null, 'bbcom' => null )); // ] } if($reject_request){ // log errors // display errors (optional) exit; } /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ echo 'Hello World!'; // ... 

Преимущество $_SERVER['HTTP_HOST'] том, что его поведение более четко определено, чем $_SERVER['SERVER_NAME'] . Контрастность ➫➫ :

Содержимое заголовка Host: из текущего запроса, если таковой имеется.

с:

Имя хоста сервера, под которым выполняется текущий скрипт.

Использование более совершенного интерфейса, такого как $_SERVER['HTTP_HOST'] означает, что большее количество SAPI реализует его с помощью надежного четкого поведения. (В отличие от другого .) Однако он все еще полностью зависит от SAPI ➫➫ :

Нет никакой гарантии, что каждый веб-сервер предоставит любую из этих записей [ $_SERVER ]; серверы могут опускать некоторые или предоставлять другим, не перечисленным здесь.

Чтобы понять, как правильно получить имя хоста, прежде всего вам нужно понять, что сервер, содержащий только код, не имеет возможности узнать (предварительное подтверждение для) своего собственного имени в сети. Он должен взаимодействовать с компонентом, который поставляет ему свое имя. Это можно сделать с помощью:

  • локальный файл конфигурации

  • локальная база данных

  • жестко закодированный исходный код

  • внешний запрос ( завиток )

  • клиент / атакующий Host: запрос

  • и т.д

Обычно это делается через локальный (SAPI) файл конфигурации. Обратите внимание, что вы правильно настроили его, например, в Apache ➫➫ :

Пара вещей должна быть «подделана», чтобы динамический виртуальный хост выглядел как обычный.

Наиболее важным является имя сервера, которое используется Apache для создания самореференциальных URL-адресов и т. Д. Оно настроено с помощью директивы ServerName , и оно доступно для CGI через переменную среды SERVER_NAME .

Фактическое значение, используемое во время выполнения, контролируется установкой UseCanonicalName.

С UseCanonicalName Off Имя сервера происходит из содержимого заголовка Host: в запросе. С UseCanonicalName DNS это происходит из обратного DNS-поиска IP-адреса виртуального хоста. Первая настройка используется для динамического виртуального хостинга на основе имен, а последняя используется для ** хостинга на базе IP.

Если Apache не может обработать имя сервера, потому что отсутствует заголовок Host: или поиск DNS не выполняется, вместо этого используется значение, настроенное с использованием ServerName .

Я не уверен и не доверяю $_SERVER['HTTP_HOST'] потому что он зависит от заголовка от клиента. По-другому, если домен, запрошенный клиентом, не мой, они не попадут на мой сайт, потому что DNS и протокол TCP / IP указывают его на правильный пункт назначения. Однако я не знаю, возможно ли захватить DNS, сеть или даже сервер Apache. Чтобы быть в безопасности, я определяю имя хоста в среде и сравниваю его с $_SERVER['HTTP_HOST'] .

Добавить SetEnv MyHost domain.com в файл .htaccess для root и добавить код в Common.php

 if (getenv('MyHost')!=$_SERVER['HTTP_HOST']) { header($_SERVER['SERVER_PROTOCOL'].' 400 Bad Request'); exit(); } 

Я включаю этот файл Common.php на каждую php-страницу. Эта страница делает все, что требуется для каждого запроса, такого как session_start() , модифицирует сеансовый файл cookie и отклоняется, если метод post поступает из другого домена.

XSS всегда будет там, даже если вы используете $_SERVER['HTTP_HOST'] , $_SERVER['SERVER_NAME'] ИЛИ $_SERVER['PHP_SELF']