質問

どちらかを使用することを検討するのはいつですか?またその理由は何ですか?

役に立ちましたか?

解決

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

いいえの場合 ServerName が指定されている場合、サーバーは IP アドレスの逆引き参照を実行してホスト名を推測しようとします。ポートが指定されていない場合は、 ServerName, の場合、サーバーは受信リクエストのポートを使用します。最適な信頼性と予測可能性を得るには、ホスト名とポートを明示的に指定する必要があります。 ServerName 指令。


アップデート:確認した後 あなたの質問に対するペッカの答え へのリンクが含まれています ボビンスの答え PHP が常に返すこと HTTP_HOSTの値 SERVER_NAME, これは、数年前の私自身の PHP 4.x + Apache HTTPD 1.2.x の経験に反するものですが、Windows XP 上の現在の XAMPP 環境 (Apache HTTPD 2.2.1 と PHP 5.2.8) を吹き飛ばして、開始しました。それを使用して、両方の値を出力する PHP ページを作成し、Java テスト アプリケーションを作成しました。 URLConnection を変更するには Host ヘッダーとテストは、これが実際に (誤って) 当てはまることを教えてくれました。

最初に PHP を疑い、いくつか調べた後 PHPのバグレポート この件に関して、問題の根本は使用されている Web サーバーにあり、HTTP が誤って返されたことがわかりました。 Host ヘッダーのとき SERVER_NAME と要求されました。そこで私は掘り下げました Apache HTTPD バグレポート 使用して さまざまなキーワード この件に関して、ついに見つけました 関連するバグ. 。この動作は、Apache HTTPD 1.3 あたりから導入されました。設定する必要があります UseCanonicalName への指令 on の中に <VirtualHost> のエントリー ServerNamehttpd.conf (下部の警告も確認してください) 文書!).

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

これは私にとってはうまくいきました。

要約すると、 SERVER_NAME のほうが信頼できるけど、あなたは 依存 サーバー設定上で!

他のヒント

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

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

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

共通のかもしれないとして

として、私はに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'

あなたが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://%{SERVER_NAME}/

# HTTP_HOST will work - Redirection to https://[::1]/
RewriteRule .* https://%{HTTP_HOST}/

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

あなたがserver.phpというか、今まで何を次のようにそれを呼び出すようにしたいを通じて確認する場合:

<?php

phpinfo(INFO_VARIABLES);

?>

または

<?php

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

print_r($_SERVER);

?>

次に、あなたのサイトのすべての有効なURLでアクセスして違いをチェックします。

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

これは、の意味人のSERVER_NAMEがより信頼性のある "何かを理解するために私にしばらく時間がかかりました。私は、共有サーバーを使用して、仮想ホストディレクティブにアクセスすることはできません。だから、私は別のディレクトリに異なる.htaccesssをマッピングするためにHTTP_HOSTでのmod_rewriteを使用しています。その場合には、意味のあるHTTP_HOSTである。

1用途の名前ベースのバーチャルホストの場合は、

状況は似ています。仮想ホスト内のServerNameディレクティブは、単純にホスト名がこの仮想ホストにマップされると言います。一番下の行は、両方の場合に、要求(HTTP_HOST)中にクライアントによって提供されるホスト名が、それ自体がディレクトリにマップされているサーバ内の名前と一致しなければならない、ということです。マッピングは、仮想ホストのディレクティブまたはhtaccessのmod_rewriteのルールで行われているかどうかはここでは二次的です。これらのケースでは、HTTP_HOSTSERVER_NAMEと同じになります。私は、Apacheがそのように設定されていることを嬉しく思います。

しかし、状況はIPベースのバーチャルホストと異なっています。この場合のみ、この場合には、今クライアントはIPによって、名前ではなく、サーバーを選択しているためSERVER_NAMEHTTP_HOSTは、異なる可能性があります。を実際に、これは重要である特別な設定があるかもしれません。

だから、今から始めて、私は私のコードは、これらの特別な構成に移植されただけの場合には、SERVER_NAMEを使用します。

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

PHP の意味では、 $_SERVER['SERVER_NAME'] PHP が $_SERVER Apache 構成に基づくスーパーグローバル (**ServerName** ディレクティブ UseCanonicalName On ) httpd.conf 内 (含まれている仮想ホスト構成ファイルなどからのものであっても...)。 HTTP_ホスト 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'] 値 (最終的には要求された値から導出されます) host HTTP ヘッダー)が一致する $_SERVER['SERVER_NAME'].

さて、私はスーパーグローバルな話を使って私の例を説明していますが、それは単に、このことに慣れていない人もいるからです。 INPUT_GET, INPUT_POST, 、 そして INPUT_SERVER に関してで filter_input_array().

肝心なのは、次の場合を除き、サーバー上で POST リクエストを処理しないということです。 全て という4つの条件が満たされています。したがって、POST リクエストに関しては、HTTP の提供に失敗すると、 host ヘッダー (以前に存在をテストした) 呪文 運命 厳格な HTTP 1.0 ブラウザ。また、要求されたホストは 値と一致する必要があります のために ServerName の中に httpd.conf, 、そして拡張により、の値 $_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の設定で変更することができ、サーバーのサーバー名の設定やファイアウォールそれはあなたとサーバーの間とすることができると述べています。

次の関数は、常にポートせずに、実際のホスト(ユーザー入力されたホスト)を返し、それはほとんど信頼性があります:

function getRealHost(){
   list($realHost,)=explode(':',$_SERVER['HTTP_HOST']);
   return $realHost;
}
ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top