185

私は多くの検索を行い、PHP $_SERVER docsも読みました。サイト全体で使用される単純なリンク定義用の PHP スクリプトに使用するものに関して、私にはこの権利がありますか?

$_SERVER['SERVER_NAME']Web サーバーの構成ファイル (私の場合は Apache2) に基づいており、(1) VirtualHost、(2) ServerName、(3) UseCanonicalName などのいくつかのディレクティブによって異なります。

$_SERVER['HTTP_HOST']クライアントからのリクエストに基づいています。

したがって、スクリプトを可能な限り互換性のあるものにするために使用する適切なものは$_SERVER['HTTP_HOST']. この仮定は正しいですか?

フォローアップ コメント:

$_SERVERこの記事を読んで、一部の人々が「どのvarsも信用しないだろう」と言ったことに気付いた後、私は少し偏執症になったと思います。

どうやら議論は主に$_SERVER['PHP_SELF']、XSS攻撃を防ぐために適切にエスケープせずにフォームアクション属性でそれを使用すべきではない理由についてです。

上記の最初の質問に対する私の結論は$_SERVER['HTTP_HOST']、フォームで使用されている場合でも、XSS 攻撃を心配することなく、サイト上のすべてのリンクに使用しても「安全」であるということです。

私が間違っている場合は、私を修正してください。

4

9 に答える 9

166

それはおそらく誰もが最初に考えたことです。しかし、それはもう少し難しいです。Chris Shiflett の記事SERVER_NAMEVersusHTTP_HOSTを参照してください。

銀の弾丸はないようです。Apache に正規名を使用するように強制する場合にのみ、常に正しいサーバー名を取得できますSERVER_NAME

したがって、それを使用するか、ホスト名をホワイトリストと照合して確認します。

$allowed_hosts = array('foo.example.com', 'bar.example.com');
if (!isset($_SERVER['HTTP_HOST']) || !in_array($_SERVER['HTTP_HOST'], $allowed_hosts)) {
    header($_SERVER['SERVER_PROTOCOL'].' 400 Bad Request');
    exit;
}
于 2009-09-22T12:25:45.917 に答える
91

追加のメモ - サーバーが 80 以外のポートで実行されている場合 (開発/イントラネット マシンでは一般的であるように) HTTP_HOST、ポートは含まれますが、含まれSERVER_NAMEません。

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

(少なくとも、Apacheポートベースの仮想ホストで気づいたことです)

Mike が以下で述べているように、 HTTPS で実行している場合は含まれHTTP_HOSTませ:443(テストしていない非標準ポートで実行している場合を除きます)。

于 2012-08-21T00:02:45.570 に答える
33

どちらかを使用してください。多くの場合、SERVER_NAME はとにかく HTTP_HOST から入力されるだけなので、どちらも同じように (不) 安全です。私は通常、HTTP_HOST を使用します。これにより、ユーザーは開始時の正確なホスト名にとどまります。たとえば、.com ドメインと .org ドメインに同じサイトがある場合、.org から .com に誰かを送信したくありません。他のドメイン。

いずれにせよ、Web アプリケーションが既知の適切なドメインに対してのみ応答することを確認する必要があります。これは、(a) Gumbo のようなアプリケーション側のチェックを使用するか、(b)不明な Host ヘッダーを与える要求に応答しない、必要なドメイン名で仮想ホストを使用することによって実行できます。

この理由は、あなたのサイトが古い名前でアクセスされることを許可すると、DNS 再バインド攻撃 (別のサイトのホスト名があなたの IP を指し、ユーザーが攻撃者のホス​​ト名であなたのサイトにアクセスし、次にホスト名攻撃者の IP に移動され、Cookie/認証が取得されます) および検索エンジンのハイジャック (攻撃者がサイトで自分のホスト名をポイントし、検索エンジンにそれを「最適な」プライマリ ホスト名として認識させようとする場合)。

どうやら議論は主に $_SERVER['PHP_SELF'] と、XSS 攻撃を防ぐために適切にエスケープせずにフォーム アクション属性でそれを使用してはならない理由についてです。

Pfft。でエスケープせずに、どの属性でも何も使用しないでください。そのため、サーバー変数について特別なことは何もありません。htmlspecialchars($string, ENT_QUOTES)

于 2009-09-22T17:24:34.557 に答える
26

これは、Symfony がホスト名を取得するために使用するものの詳細な翻訳です (より文字通りの翻訳については、2 番目の例を参照してください)。

function getHost() {
    $possibleHostSources = array('HTTP_X_FORWARDED_HOST', 'HTTP_HOST', 'SERVER_NAME', 'SERVER_ADDR');
    $sourceTransformations = array(
        "HTTP_X_FORWARDED_HOST" => function($value) {
            $elements = explode(',', $value);
            return trim(end($elements));
        }
    );
    $host = '';
    foreach ($possibleHostSources as $source)
    {
        if (!empty($host)) break;
        if (empty($_SERVER[$source])) continue;
        $host = $_SERVER[$source];
        if (array_key_exists($source, $sourceTransformations))
        {
            $host = $sourceTransformations[$source]($host);
        } 
    }

    // Remove port number from host
    $host = preg_replace('/:\d+$/', '', $host);

    return trim($host);
}

古い:

これは、Symfony フレームワークで使用される、あらゆる方法でホスト名を取得しようとするメソッドを、ベスト プラクティスに従って PHP に翻訳したものです。

function get_host() {
    if ($host = $_SERVER['HTTP_X_FORWARDED_HOST'])
    {
        $elements = explode(',', $host);

        $host = trim(end($elements));
    }
    else
    {
        if (!$host = $_SERVER['HTTP_HOST'])
        {
            if (!$host = $_SERVER['SERVER_NAME'])
            {
                $host = !empty($_SERVER['SERVER_ADDR']) ? $_SERVER['SERVER_ADDR'] : '';
            }
        }
    }

    // Remove port number from host
    $host = preg_replace('/:\d+$/', '', $host);

    return trim($host);
}
于 2012-01-18T11:46:03.857 に答える
8

2つの主な違いは、$_SERVER['SERVER_NAME']はサーバー制御変数であり、$_SERVER['HTTP_HOST']はユーザー制御値であるということです。

経験則では、ユーザーからの値を決して信頼しないことです。そのため$_SERVER['SERVER_NAME']、より適切な選択です。

Gumboが指摘したように、を設定しない場合、Apacheはユーザー指定の値からSERVER_NAMEを構築しますUseCanonicalName On

編集:そうは言っても、サイトが名前ベースの仮想ホストを使用している場合、HTTPホストヘッダーは、デフォルトサイトではないサイトに到達する唯一の方法です。

于 2009-09-22T13:45:53.397 に答える
3

$_SERVER['HTTP_HOST']クライアントからのヘッダーに依存するため、よくわかりません。別の方法として、クライアントが要求したドメインが私のものでない場合、DNS と TCP/IP プロトコルが正しい宛先を指しているため、クライアントは私のサイトにアクセスできません。ただし、DNS、ネットワーク、さらには Apache サーバーをハイジャックできるかどうかはわかりません。安全のために、環境でホスト名を定義し、それと比較し$_SERVER['HTTP_HOST']ます。

ルートに .htaccess ファイルを追加SetEnv MyHost domain.comし、Common.php にこのコードを追加します。

if (getenv('MyHost')!=$_SERVER['HTTP_HOST']) {
  header($_SERVER['SERVER_PROTOCOL'].' 400 Bad Request');
  exit();
}

この Common.php ファイルをすべての php ページに含めます。session_start()このページは、セッション Cookie の変更、ポスト メソッドが別のドメインからのものである場合の拒否など、各リクエストに必要な処理を行います。

于 2010-03-15T01:08:25.653 に答える
1

XSS$_SERVER['HTTP_HOST']$_SERVER['SERVER_NAME']ORを使用しても、常に存在します。$_SERVER['PHP_SELF']

于 2014-01-10T09:48:40.347 に答える