PHP の HTTP_HOST と SERVER_NAME の違いは何ですか?
-
21-09-2019 - |
質問
どちらかを使用することを検討するのはいつですか?またその理由は何ですか?
解決
の 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>
のエントリー ServerName
で httpd.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
がより信頼性のある "何かを理解するために私にしばらく時間がかかりました。私は、共有サーバーを使用して、仮想ホストディレクティブにアクセスすることはできません。だから、私は別のディレクトリに異なる.htaccess
sをマッピングするためにHTTP_HOST
でのmod_rewriteを使用しています。その場合には、意味のあるHTTP_HOST
である。
状況は似ています。仮想ホスト内のServerName
ディレクティブは、単純にホスト名がこの仮想ホストにマップされると言います。一番下の行は、両方の場合に、要求(HTTP_HOST
)中にクライアントによって提供されるホスト名が、それ自体がディレクトリにマップされているサーバ内の名前と一致しなければならない、ということです。マッピングは、仮想ホストのディレクティブまたはhtaccessのmod_rewriteのルールで行われているかどうかはここでは二次的です。これらのケースでは、HTTP_HOST
はSERVER_NAME
と同じになります。私は、Apacheがそのように設定されていることを嬉しく思います。
のしかし、状況はIPベースのバーチャルホストと異なっています。この場合のみ、この場合には、今クライアントはIPによって、名前ではなく、サーバーを選択しているためSERVER_NAME
とHTTP_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;
}