Pregunta

Cuando se considere el uso de uno sobre el otro y por qué?

¿Fue útil?

Solución

El HTTP_HOST se obtiene de la solicitud HTTP de cabecera y esto es lo que el cliente utiliza realmente como "host de destino" de la solicitud. El SERVER_NAME se define en la configuración del servidor. Cuál utilizar depende de lo que lo necesita. Ahora debería sin embargo se da cuenta de que una es un valor cliente-controlado que por lo tanto no puede ser fiable para su uso en la lógica de negocio y el otro es un valor controlada por el servidor que es más fiable. Sin embargo, tendrá que asegurarse de que el servidor web en cuestión ha configurado correctamente el SERVER_NAME. Tomando Apache HTTPD como ejemplo, he aquí un extracto de su documentación :

  

Si no se especifica ningún ServerName, a continuación, los intentos de servidor para deducir el nombre de host haciendo una busqueda reversa en la dirección IP. Si no se especifica ningún puerto en el ServerName, entonces el servidor usará el puerto para las peticiones entrantes. Para mayor fiabilidad y previsibilidad óptimo, debe especificar un nombre de host y el puerto explícita usando la directiva ServerName.


Actualizar Pekka en su pregunta que contiene un enlace a respuesta de bobince que PHP siempre devolvería el valor de HTTP_HOST para SERVER_NAME, lo que va en contra de mi propio PHP 4.x + Apache HTTPD 1.2.x experiencias de una hace dos años, me sopló un poco de polvo de mi entorno actual XAMPP en Windows XP (Apache HTTPD 2.2.1 con PHP 5.2.8), que se inició, crearon una página PHP que imprime los valores de ambos, crearon una aplicación de prueba Java utilizando < a href = "http://docs.oracle.com/javase/8/docs/api/java/net/URLConnection.html" rel => URLConnection para modificar el encabezado y pruebas Host "noreferrer" me enseñaron que esto es de hecho (incorrectamente) el caso.

Después de la primera sospechar PHP y cavar en algunos PHP error informes sobre el tema, he aprendido que la raíz del problema está en el servidor web utilizado, que incorrectamente volvió HTTP Host cabecera cuando se solicitó SERVER_NAME. Y cavé en Apache HTTPD informes de errores con respecto al tema y, finalmente, me encontré con un relacionada fallo . Este comportamiento se introdujo desde alrededor de Apache HTTPD 1.3. Es necesario configurar UseCanonicalName directiva para on en la entrada de <VirtualHost> la ServerName en httpd.conf (consultar también la advertencia en la parte inferior de el documento !).

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

Esto funcionó para mí.

Resumido, SERVER_NAME es más fiable, pero eres depende en la configuración del servidor!

Otros consejos

HTTP_HOST es el host de destino enviado por el cliente. Puede ser manipulado libremente por el usuario. No es ningún problema para enviar una petición a su sitio pidiendo un valor de HTTP_HOST www.stackoverflow.com.

SERVER_NAME proviene de definición VirtualHost del servidor y por lo tanto se considera más fiable. Puede, sin embargo, también se puede manipular desde el exterior, bajo ciertas condiciones relacionadas con la forma en que su servidor web está configurado: Ver este Esta pregunta SO que se ocupa de los aspectos de seguridad de ambas variaciones.

No se debe confiar a uno y otro para estar seguro. Dicho esto, lo que debe utilizar realmente depende de lo que quiere hacer. Si desea determinar qué dominio se ejecuta un script, usted puede utilizar con seguridad HTTP_HOST, siempre y cuando los valores no válidos procedentes de un usuario malicioso no puede romper nada.

Como he mencionado en esta respuesta , si se ejecuta el servidor en un puerto que no sea 80 (como podría ser común en un desarrollo / máquina de intranet), entonces HTTP_HOST contiene el puerto, mientras que SERVER_NAME no lo hace.

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

(al menos eso es lo que he notado en VirtualHosts basadas en puertos Apache)

Tenga en cuenta que HTTP_HOST hace no contienen :443 cuando se ejecuta en HTTPS (a no ser que se está ejecutando en un puerto no estándar, que no he probado).

Como otros han señalado, los dos también difieren cuando se utiliza IPv6:

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

Tenga en cuenta que si desea utilizar IPv6, es probable que desea utilizar en lugar de HTTP_HOST SERVER_NAME. Si introduce http://[::1]/ las variables de entorno será el siguiente:

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

Esto significa que, si lo hace un mod_rewrite por ejemplo, es posible obtener un resultado desagradable. Ejemplo para un redireccionamiento 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}/

Esto se aplica sólo si accede al servidor sin una hostname.

Si desea comprobar a través de un server.php o lo que sea que quieras llamarlo con lo siguiente:

<?php

phpinfo(INFO_VARIABLES);

?>

o

<?php

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

print_r($_SERVER);

?>

A continuación, acceder a ella con todas las URL válidas para su sitio y ver la diferencia.

Depende de lo que yo quiero averiguar. SERVER_NAME es el nombre de host del servidor, mientras HTTP_HOST es la máquina virtual que el cliente conectado.

Me tomó un tiempo para entender lo que la gente entiende por"SERVER_NAME es más fiable'.Yo uso un servidor compartido y no tiene acceso a las directivas de host virtual.Así, puedo utilizar mod_rewrite en .htaccess asignar diferentes HTTP_HOSTs a directorios diferentes.En ese caso, es HTTP_HOST que es significativo.

La situación es similar, si uno utiliza el nombre de los hosts virtuales basados en:el ServerName la directiva dentro de un host virtual simplemente dice que el nombre de host que se asignará a este host virtual.La conclusión es que, en ambos casos, el nombre de host proporcionado por el cliente en la solicitud (HTTP_HOST), debe coincidir con un nombre en el servidor, el cual está asignado a un directorio.Si la asignación se realiza con las directivas de host virtual o con htaccess reglas de mod_rewrite es secundaria aquí.En estos casos, HTTP_HOST será el mismo SERVER_NAME.Me alegro de que Apache está configurado de esa manera.

Sin embargo, la situación es diferente con base IP de los hosts virtuales.En este caso y sólo en este caso, SERVER_NAME y HTTP_HOST puede ser diferente, porque ahora el cliente selecciona el servidor por IP, no por el nombre. De hecho, puede haber configuraciones especiales en las que esto es importante.

Así que, a partir de ahora, voy a utilizar SERVER_NAME, en caso de que mi código es portado en estas configuraciones especiales.

Si se asume una tiene una configuración simple (CentOS 7, Apache 2.4.x, y PHP 5.6.20) y sólo un sitio web (no asumir el alojamiento virtual) ...

En el sentido de PHP, $_SERVER['SERVER_NAME'] es un elemento de registros PHP en el $_SERVER superglobal función de la configuración de Apache (Directiva **ServerName** con UseCanonicalName On) en httpd.conf (ya sea desde un archivo de configuración de host virtual incluida, lo que sea, etc ... ). HTTP_HOST se deriva de la HTTP host cabecera. Tratar esto como entrada del usuario. Filtro y validar antes de usar.

Este es un ejemplo de donde uso $_SERVER['SERVER_NAME'] como base para una comparación. El siguiente método es de una clase hija de concreto hice ServerValidator llamado (el niño de Validator). ServerValidator cheques seis o siete elementos en $ _SERVER antes de usarlos.

En la determinación de si la petición HTTP es POST, utilizo este método.

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

En el momento en que este método se llama, todo el filtrado y validación de elementos $ _SERVER pertinentes se habría producido (y propiedades relevantes conjunto).

La línea ...

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

... comprueba que el valor $_SERVER['HTTP_HOST'] (en última instancia deriva de la la solicitada host cabecera HTTP) Partidos $_SERVER['SERVER_NAME'].

Ahora, estoy usando hablan superglobal para explicar mi ejemplo, pero eso es sólo porque algunas personas no están familiarizados con INPUT_GET, INPUT_POST y INPUT_SERVER en lo que respecta a filter_input_array() .

La conclusión es que no son capaces de manejar las peticiones POST en mi servidor a menos que todos se cumplen cuatro condiciones. Por lo tanto, en términos de solicitudes POST, el no proporcionar un HTTP host cabecera (presencia probado para antes) hechizos condenación para estrictos HTTP 1.0 navegadores. Por otra parte, el host solicitado debe coincidir con el valor ServerName en el httpd.conf , y, por extensión, el valor de $_SERVER('SERVER_NAME') en el $_SERVER superglobal. Una vez más, estaría usando INPUT_SERVER con las funciones de filtro PHP, pero lo que me refiero.

Tenga en cuenta que Apache utiliza con frecuencia ServerName en redirecciones estándar (tales como salir de la barra al final de un URL: ejemplo, http://www.foo.com a ser de http://www.foo.com/ ), incluso si no está utilizando la reescritura de URL.

Yo uso $_SERVER['SERVER_NAME'] como el estándar, no $_SERVER['HTTP_HOST']. Hay un montón de ida y vuelta en este tema. $_SERVER['HTTP_HOST'] podría estar vacío, por lo que esta no debe ser la base para la creación de códigos de convenciones tales como mi método público anteriormente. Sin embargo, sólo porque ambos pueden ser conjunto no garantiza que serán iguales. La prueba es la mejor manera de saber con seguridad (teniendo en cuenta la versión de Apache y PHP version).

Como dijo balusC SERVER_NAME no es fiable y se puede cambiar en configuración de Apache, nombre del servidor de configuración del servidor y servidor de seguridad que puede haber entre el usuario y el servidor.

Después de la función siempre devuelve verdadero host (anfitrión de usuario mecanografiado) sin el puerto y es casi segura:

function getRealHost(){
   list($realHost,)=explode(':',$_SERVER['HTTP_HOST']);
   return $realHost;
}
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top