PHPのHTTP_HOSTとSERVER_NAMEの違いは何ですか?


533

PHP HTTP_HOSTとの違いは何SERVER_NAMEですか?

どこ:

  • HTTP_POST === $_SERVER['HTTP_HOST']
  • SERVER_NAME === $_SERVER['SERVER_NAME']

いつ他のものを使用することを検討しますか、またその理由は何ですか


14
「私は通常HTTP_HOSTを使用するため、ユーザーは開始したときの正確なホスト名を使い続けます。たとえば、.comドメインと.orgドメインに同じサイトがある場合、.orgからに誰かを送信したくない.com、特に.orgにログイントークンがあり、他のドメインに送信すると失われる可能性がある場合」-これと、stackoverflow.com
questions /

5
@Yarin、の結果HTTP_HOSTホワイトリストで検証することを忘れないでください。それ以外の場合、攻撃者はHTTP リクエストに任意の値を入れHost:てサーバーにそれを受け入れさせることができます。
Pacerier

6
初心者:この質問は、一般的に経由して得られた値を参照している$_SERVER['HTTP_HOST']$_SERVER['SERVER_NAME']
グレゴリーコスモHaun

回答:


780

HTTP_HOST得られたHTTPリクエストヘッダと、これはクライアントが実際に要求の「ターゲットホスト」として使用されるものです。SERVER_NAMEサーバ設定で定義されています。どちらを使用するかは、それが何のために必要かによって異なります。ただし、1つはクライアント制御の値であり、ビジネスロジックでの使用には信頼性がない可能性があり、もう1つはより信頼性の高いサーバー制御の値であることを理解する必要があります。ただし、問題のWebサーバーがSERVER_NAME正しく構成されていることを確認する必要があります。Apache HTTPDを例にとると、そのドキュメントからの抜粋があります

ServerNameも指定されていない場合、サーバーはIPアドレスで逆ルックアップを実行してホスト名を推定しようとします。でポートが指定されていない場合ServerName、サーバーは着信要求からのポートを使用します。最適な信頼性と予測可能性を得るには、ServerNameディレクティブを使用して明示的なホスト名とポートを指定する必要があります。


更新:PHPが常にの値を返すというbobinceの回答へのリンクを含む質問のPekkaの回答をチェックし後、これは自分のPHP 4.x + Apache HTTPD 1.2.xの数年前の経験に反します、Windows XP(Apache HTTPD 2.2.1とPHP 5.2.8)の現在のXAMPP環境からほこりを吹き飛ばし、それを開始し、両方の値を出力するPHPページを作成し、ヘッダーの変更に使用するJavaテストアプリケーションを作成しました。テストは、これが実際に(誤って)事実であることを教えてくれました。HTTP_HOSTSERVER_NAMEURLConnectionHost

最初にPHPを疑い、件名に関するいくつかのPHPバグレポートを掘り下げた後、問題の根本は使用されているWebサーバーにあり、要求されたHostときSERVER_NAMEにHTTP ヘッダーを誤って返すことがわかりました。そこで、件名に関するさまざまなキーワードを使用してApache HTTPDバグレポート調べたところ、最終的に関連するバグが見つかりました。この動作は、Apache HTTPD 1.3以降に導入されました。あなたは、設定する必要がディレクティブに内のエントリで(もの下部に警告をチェックし、ドキュメント!)。UseCanonicalNameon<VirtualHost>ServerNamehttpd.conf

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

これでうまくいきました。

要約すると、SERVER_NAMEより信頼性が高くなりますが、サーバー構成に依存します!


5
さて、これは私の問題を解決します。これはOPとは無関係ですが、関連があります。ブラウザが提供できるものを使用することで、セキュリティの問題を非常に心配しました。この答えは非常に役に立ちました。まとめていただきありがとうございます。
Yitzhak 2013年

2
なぜHTTP_HOSTは信頼できないと言うのですか?はい、それはユーザーによって提供されますが、ユーザーが偽の値を指定した場合、サーバー構成は自動的に503を返し、PHPスクリプトは実行されません!
ペーチェリエ2013

1
@Pacerier:この回答を書いている時点では、そうではありませんでした。バージョンは回答に記載されています。PHPについていけなくなったので、新しいバージョンで実際に変更されたかどうかはわかりません。
BalusC 2013

2
WinXPからApacheを騙す簡単な方法は、「hosts」ファイルに、「127.0.0.1 mydomain.com」のようにサーバーのIPが別のドメインに割り当てられていることを示す行を追加することです。私はこれを何度も使用して、インターネット接続とサイトの読み込みが非常に高速であるとユーザーに騙してローカルWebサイトを表示させました。別の方法で、「173.194.41.5 localhost」を使用して、Apacheをだましてローカルで実行されていると思わせることができるので、Apacheが適切に構成されていることが確実でない限り、SERVER_NAMEを完全に信頼しないでください。
vicenteherrera 2013年

1
追加したいのは、NGINX + PHP-FPMがserver_nameディレクティブによって設定された値を返すことです。特にno server_nameが設定されている場合も_SERVER["SERVER_NAME"]空になります。
white_gecko 2014年

69

HTTP_HOSTクライアントが送信したターゲットホストです。ユーザーが自由に操作できます。のHTTP_HOST値を要求するリクエストをサイトに送信することは問題ありませんwww.stackoverflow.com

SERVER_NAMEサーバーのVirtualHost定義に由来するため、より信頼性が高いと見なされます。ただし、Webサーバーの設定方法に関連する特定の条件下では、外部から操作することもできます。両方のバリエーションのセキュリティの側面を扱うこのSOの質問を参照してください。

安全のためにどちらにも頼るべきではありません。つまり、何を使用するかは、実際に何をしたいかによって異なります。スクリプトが実行されているドメインを特定する場合はHTTP_HOST、悪意のあるユーザーからの無効な値が何も壊さない限り、安全に使用できます。


8
はい。ただし、www.stackoverflow.comのHTTP_HOST値を要求するリクエストは、ほとんどのHTTPサーバーによって拒否されるため、PHPスクリプトはリクエストを認識しません。
ペーチェリエ2013

2
@Pacerierはtrueですが、サーバーが適切に構成されていない場合は常にそうとは限りません。
ペッカ

1
BalusCの投稿で述べたように、IPでApache仮想ホストにアクセスすると、これらの変数の両方に、実際のサーバー名ではなくIP(デフォルト)が含まれます。実際のサーバー名になるようUseCanonicalName onに強制SERVER_NAMEするには、httpd.confで使用する必要があります。
Simon East

@Pekka웃、サーバーが適切に構成されていない場合、$_SERVER['SERVER_NAME']同様に機能しません。正しく構成されていないサーバーは$_SERVER['SERVER_NAME']、クライアントのHost:要求の値に基づいて設定されます。どちらも同じです。
Pacerier 2015年

良い答えですが、仮想ホスティングを想定していません。
Anthony Rutledge 2017年

55

この回答で述べたように、サーバーが80以外のポートで実行されている場合(開発/イントラネットマシンでは一般的である可能性があります)HTTP_HOST、ポートは含まれていますが、含まれてSERVER_NAMEいません。

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

(少なくとも、それはApacheのポートベースの仮想ホストで気付いたものです)

HTTPSで実行している場合含まれないことに注意しHTTP_HOSTてください(テストしていない非標準ポートで実行している場合を除く)。:443

他の人が指摘したように、IPv6を使用する場合も2つは異なります。

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

2
彼らはいつこの狡猾な行動を修正しますか?
Pacerier

27

IPv6を使用する場合HTTP_HOSTは、ではなく使用したいことに注意してくださいSERVER_NAMEhttp://[::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}/

これは、ホスト名なしでサーバーにアクセスする場合にのみ適用されます。


1
SiteGround、社内のhttpからhttpsへのリダイレクトコードで使用https://%{SERVER_NAME}%{REQUEST_URI}
IXN

6

server.phpなどをチェックしたい場合は、次のように呼び出します。

<?php
    phpinfo(INFO_VARIABLES);
?>

または

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

    print_r($_SERVER);
?>

次に、サイトに有効なすべてのURLでアクセスし、違いを確認します。


5

私が知りたいことに依存します。SERVER_NAMEはサーバーのホスト名で、HTTP_HOSTはクライアントが接続した仮想ホストです。


4
正確には本当のローランドでSERVER_NAMEはありません。通常はサーバー自体ではなく、VirtualHostの名前です。そして、Apacheでは、SERVER_NAMEしばしば同じ値が入力されますHTTP_HOST(BalusCの回答を参照)。
Simon East

1
@Simon、ほとんどのホストがVirtualHostになったので、「サーバー自体」の名前はどういう意味ですか?
Pacerier

1つのWebサイトで仮想プライベートサーバー(VPS)を実行している場合SERVER_NAME、仮想ホストに適用されると想定する必要はありません。ただし、1つのサイトで仮想ホスト設定を使用することはできます。多くの人が共有ホスティングを使用しているので、私はあなたの主張を理解しています。
Anthony Rutledge 2017年

2

人々が「SERVER_NAMEより信頼できる」とはどういう意味か理解するのにしばらく時間がかかりました。共有サーバーを使用していますが、仮想ホストディレクティブにアクセスできません。そこで、mod_rewrite inを使用して.htaccess 、異なるHTTP_HOSTを異なるディレクトリにマップします。その場合、それHTTP_HOSTは意味があります。

名前ベースの仮想ホストを使用している場合も同様です。ServerName仮想ホスト内のディレクティブは、この仮想ホストにマップされるホスト名を示すだけです。結論として、どちらの場合も、要求(HTTP_HOST)中にクライアントによって提供されたホスト名は、サーバー内の名前と一致する必要があり、サーバー自体がディレクトリにマップされます。マッピングが仮想ホストディレクティブで行われるか、htaccess mod_rewriteルールで行われるかは、ここでは二次的なものです。これらの場合、HTTP_HOSTはと同じになりSERVER_NAMEます。Apacheがそのように構成されていることをうれしく思います。

ただし、IPベースの仮想ホストでは状況が異なります。この場合のみ、このケースでは、SERVER_NAMEHTTP_HOST今クライアントは名前ではなく、IPでサーバーを選択しているため、異なる場合があります。 実際、これが重要な特別な構成があるかもしれません。

したがって、今からSERVER_NAMEコードをこれらの特別な構成で移植する場合に備えて、を使用します。


2

簡単な設定(CentOS 7、Apache 2.4.x、およびPHP 5.6.20)と、1つのWebサイト(仮想ホスティングを想定していない)のみがあると仮定します...

PHPの意味で$_SERVER['SERVER_NAME']は、httpd.conf内の$_SERVERApache構成(を使用した**ServerName**ディレクティブUseCanonicalName On)に基づいて、PHPがスーパーグローバルに登録する要素です(含まれている仮想ホスト構成ファイルなどから)。HTTP_HOSTは、HTTP hostヘッダーから派生します。これをユーザー入力として扱います。使用する前にフィルタリングして検証します。

$_SERVER['SERVER_NAME']これは、比較の基準として使用する場所の例です。次のメソッドは、私が名前を付けた具体的な子クラスからのものですServerValidator(の子Validator)。ServerValidator$ _SERVERの6つまたは7つの要素を使用する前にチェックします。

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']値(要求されたhostHTTPヘッダーから最終的に派生)がと一致することを確認します$_SERVER['SERVER_NAME']

今、私は私の例を説明するためにスーパーグローバル話すを使用していますが、それは一部の人々はに慣れていないという理由だけでINPUT_GETINPUT_POSTINPUT_SERVERの点でへfilter_input_array()

要するに、4つの条件がすべて満たされない限り、サーバーでPOST要求を処理しません。したがって、POSTリクエストに関して、厳密なHTTP 1.0ブラウザーでは、HTTP hostヘッダー(以前にテストされた存在についてテスト済み)の提供に失敗すると運命破ります。また、要求されたホストは、値が一致しなければならないためにhttpd.confのため、拡張子によって、値を、およびでスーパーグローバル。繰り返しますが、私はPHPフィルター関数を使用していますが、私のドリフトをキャッチします。ServerName$_SERVER('SERVER_NAME')$_SERVERINPUT_SERVER

Apacheが頻繁に使用していることに注意してくださいServerName標準リダイレクト:(例、そのようなURLオフ最後のスラッシュを残すようhttp://www.foo.comになってきてhttp://www.foo.com/あなたがない場合でも、) URL書き換えを使用します。

私は$_SERVER['SERVER_NAME']ではなく、標準として使用し$_SERVER['HTTP_HOST']ます。この問題については、多くの点が前後しています。 $_SERVER['HTTP_HOST']空である可能性があるため、これは上記の私のパブリックメソッドなどのコード規則を作成するための基礎にはなりません。しかし、両方が設定されているからといって、それらが等しいことを保証するものではありません。テストは確実に知る最良の方法です(ApacheバージョンとPHPバージョンを念頭に置いてください)。


0

balusCが言ったように、SERVER_NAMEは信頼性が低く、Apache config、サーバーのサーバー名構成、およびユーザーとサーバーの間のファイアウォールで変更できます。

次の関数は常に実際のホスト(ユーザーが入力したホスト)をポートなしで返し、ほぼ信頼性があります。

function getRealHost(){
   list($realHost,)=explode(':',$_SERVER['HTTP_HOST']);
   return $realHost;
}

0

$ _SERVER ['SERVER_NAME']はWebサーバーの設定に基づいています。 $ _SERVER ['HTTP_HOST']は、クライアントからの要求に基づいています。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.