Domanda

Quando volete considerare l'utilizzo di uno sopra l'altro e perché?

È stato utile?

Soluzione

Il HTTP_HOST è ottenuto dalla HTTP richiesta intestazione e questo è ciò che il cliente effettivamente utilizzato come "host di destinazione" della richiesta. Il SERVER_NAME è definito nella configurazione del server. Quale usare dipende da che cosa avete bisogno per. Si dovrebbe ora però rendersi conto che quello è un valore client-controllato che non può quindi essere affidabile per l'uso in logica di business e l'altro è un valore del server controllato, che è più affidabile. È tuttavia necessario assicurarsi che il server web in questione è il SERVER_NAME configurato correttamente. Prendendo Apache HTTPD come esempio, ecco un estratto da sua documentazione :

  

Se non viene specificato alcun ServerName, quindi il server tenta di dedurre il nome dell'host eseguendo una ricerca inversa sull'indirizzo IP. Se non porta viene specificato nella ServerName, allora il server utilizzerà la porta dalla richiesta in arrivo. Per l'affidabilità e prevedibilità ottimale, è necessario specificare un nome host esplicito e porta utilizzando la direttiva ServerName.


Aggiorna : dopo la risposta di Pekka sulla sua domanda quali contiene un link a la risposta di bobince che PHP sarebbe sempre ritornare il valore di HTTP_HOST per SERVER_NAME, che va contro la mia esperienza 1.2.x Apache HTTPD proprio PHP 4.x + da un paio di anni fa, ho saltato un po 'di polvere dal mio attuale ambiente di XAMPP su Windows XP (Apache HTTPD 2.2.1 con PHP 5.2.8), ha iniziato, ha creato una pagina PHP che stampa i valori di entrambi, ha creato un'applicazione di test Java utilizzando < a href = "http://docs.oracle.com/javase/8/docs/api/java/net/URLConnection.html" rel = "noreferrer"> URLConnection per modificare l'intestazione Host e le prove mi ha insegnato che questo è davvero (erroneamente) il caso.

Dopo la prima sospettare PHP e scavando in alcuni bug di PHP rapporti per quanto riguarda il soggetto, ho imparato che la radice del problema è nel web server utilizzato, che in modo non corretto restituito nell'intestazione HTTP Host quando è stato richiesto SERVER_NAME. Così ho scavato nel Apache HTTPD varie parole chiave per quanto riguarda il soggetto e ho finalmente trovato un relativo bug . Questo comportamento è stato introdotto dal giro Apache HTTPD 1.3. È necessario impostare UseCanonicalName direttiva on nella voce di <VirtualHost> il ServerName in httpd.conf (controllare anche l'avvertimento in fondo il documento !).

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

Questo ha funzionato per me.

Riassumendo, SERVER_NAME è più affidabile, ma sei dipendenti sulla configurazione del server!

Altri suggerimenti

HTTP_HOST è l'host di destinazione inviato dal client. Può essere manipolato liberamente dall'utente. Non è un problema per inviare una richiesta al tuo sito chiedendo per un valore di HTTP_HOST www.stackoverflow.com.

SERVER_NAME deriva dalla definizione VirtualHost del server ed è pertanto considerato più affidabile. Si può, tuttavia, anche essere manipolato dall'esterno a determinate condizioni relative al modo in cui il web server è configurato: Vedere questo Questa domanda SO che si occupa di aspetti di sicurezza di entrambe le varianti.

Si consiglia di non fare affidamento su entrambi per essere sicuri. Detto questo, cosa usare in realtà dipende da cosa si vuole fare. Se si desidera determinare quale dominio lo script è in esecuzione, si può tranquillamente utilizzare HTTP_HOST valori finché non validi provenienti da un utente malintenzionato non può rompere nulla.

Come ho detto nel questa risposta , se il server viene eseguito su una porta diversa dalla 80 (come potrebbe essere comune su uno sviluppo / intranet macchina) allora HTTP_HOST contiene la porta, mentre SERVER_NAME non è così.

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

(Almeno questo è quello che ho notato in Apache VirtualHosts basate su porte)

Si noti che HTTP_HOST non contengono :443 se in esecuzione su HTTPS (a meno che non si sta eseguendo su una porta non standard, che non ho ancora testato).

Come altri hanno notato, i due differiscono anche quando si utilizza IPv6:

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

Si prega di notare che se si desidera utilizzare IPv6, probabilmente si desidera utilizzare HTTP_HOST piuttosto che SERVER_NAME. Se si immette http://[::1]/ le variabili di ambiente sarà il seguente:

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

Questo significa, che se si fa un mod_rewrite, per esempio, si potrebbe ottenere un risultato brutto. Esempio per un reindirizzamento 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}/

Questo vale solo se si accede al server senza un nome host.

se si desidera controllare tramite un server.php o che cosa mai si desidera chiamare con il seguente:

<?php

phpinfo(INFO_VARIABLES);

?>

o

<?php

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

print_r($_SERVER);

?>

Poi accedervi con tutti gli URL validi per il tuo sito e controllare la differenza.

Dipende quello che voglio scoprire. SERVER_NAME è il nome host del server, mentre HTTP_HOST è l'host virtuale che il client connesso.

Mi c'è voluto un po 'per capire cosa la gente significava da 'SERVER_NAME è più affidabile'. Io uso un server condiviso e non ha accesso alle direttive host virtuale. Quindi, io uso mod_rewrite in .htaccess per mappare diversi HTTP_HOSTs a directory diverse. In tal caso, è HTTP_HOST che è significativo.

La situazione è simile, se si utilizza il nome host virtuali basati: la direttiva ServerName all'interno di un host virtuale dice semplicemente che hostname verrà mappata a questo host virtuale. La linea di fondo è che, in entrambi i casi, il nome host fornito dal cliente durante la richiesta (HTTP_HOST), deve essere abbinato con un nome all'interno del server, a sua volta mappato a una directory. Se la mappatura è fatto con le direttive dell'host virtuale o con le regole mod_rewrite .htaccess è secondario qui. In questi casi, HTTP_HOST sarà lo stesso di SERVER_NAME. Sono contento che Apache è configurato in questo modo.

Tuttavia, la situazione è diversa con host virtuali basati su IP. In questo caso, e solo in questo caso, SERVER_NAME e HTTP_HOST può essere diverso, perché ora il client seleziona il server da IP, non per il nome. , infatti, ci potrebbero essere delle configurazioni speciali in cui questo è importante.

Quindi, a partire da oggi, userò SERVER_NAME, nel caso in cui il mio codice è portato in queste configurazioni speciali.

Supponendo che uno ha una semplice impostazione (CentOS 7, Apache 2.4.x, e PHP 5.6.20) e solo un sito web (senza assumere hosting virtuale) ...

Nel senso PHP, $_SERVER['SERVER_NAME'] è un elemento registri PHP nel superglobale $_SERVER in base alla configurazione di Apache (direttiva **ServerName** con UseCanonicalName On) in httpd.conf (sia esso da un file di configurazione dell'host virtuale incluso, qualunque sia, ecc ... ). HTTP_HOST è derivato dal intestazione host HTTP. Trattare questo come input dell'utente. Filtrare e convalidare prima di utilizzare.

Ecco un esempio di dove io uso $_SERVER['SERVER_NAME'] come base per un confronto. Il seguente metodo è da una classe figlia di cemento ho fatto chiamato ServerValidator (figlio di Validator). ServerValidator controlla sei o sette elementi in $ _SERVER prima del loro utilizzo.

Nel determinare se la richiesta HTTP POST è, io uso questo metodo.

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

Con il tempo questo metodo è chiamato, tutti i filtri e validazione dei relativi elementi $ _SERVER sarebbe verificato (e proprietà rilevanti set).

La linea ...

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

... controlla che il valore $_SERVER['HTTP_HOST'] (in ultima analisi, derivato dal nell'intestazione HTTP host richiesto) corrisponde $_SERVER['SERVER_NAME'].

Ora, sto usando parlare superglobale di spiegare il mio esempio, ma che è solo perché alcune persone non hanno familiarità con INPUT_GET, INPUT_POST, e INPUT_SERVER per quanto riguarda filter_input_array() .

La linea di fondo è, non gestire le richieste di post sul mio server a meno che tutti quattro condizioni sono soddisfatte. Quindi, in termini di richieste POST, il mancato conferimento un'intestazione HTTP host (presenza testato per prima) incantesimi Doom per severe HTTP 1.0 browser. Inoltre, l'host richiesto deve corrispondere al valore ServerName in httpd.conf , e, per estensione, il valore per $_SERVER('SERVER_NAME') nel $_SERVER superglobale. Anche in questo caso, sarei usando INPUT_SERVER con le funzioni di filtro PHP, ma mi spiego.

Tieni presente che Apache usa frequentemente ServerName in redirect standard (come ad esempio lasciando la slash via un URL: Esempio, http://www.foo.com di diventare http://www.foo.com/ ), anche se non si utilizza la riscrittura degli URL.

Io uso $_SERVER['SERVER_NAME'] come standard, non $_SERVER['HTTP_HOST']. Ci sono un sacco di avanti e indietro su questo tema. $_SERVER['HTTP_HOST'] potrebbe essere vuoto, quindi questo non dovrebbe essere la base per la creazione di convenzioni di codice come il mio metodo pubblico sopra. Ma, proprio perché entrambi possono essere impostati non garantisce che saranno uguali. Il test è il modo migliore per sapere con certezza (tenendo presente la versione di Apache e la versione di PHP).

Come balusC detto NOME_SERVER non è affidabile e può essere modificato nella configurazione di Apache, il nome del server di configurazione di server e firewall che può essere tra voi e server.

Dopo la funzione ritorna sempre host reale (utente ha digitato host), senza la porta ed è quasi sicuro:

function getRealHost(){
   list($realHost,)=explode(':',$_SERVER['HTTP_HOST']);
   return $realHost;
}
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top