PHP$_SERVER['HTTP_HOST']与$_SERVER['SERVER_NAME'],我了解男人的网页是否正确?

StackOverflow https://stackoverflow.com/questions/1459739

  •  12-09-2019
  •  | 
  •  

我做了很多的搜索和阅读PHP $_SERVER文档.我有这个权利对于其使用对于我PHP scripts为简单的链接使用的定义在我的网站?

$_SERVER['SERVER_NAME'] 是根据你的网服务器的配置文件(Apache2在我的情况),并且根据一些指示:(1)虚拟主机,(2)服务器名称,(3)UseCanonicalName,等等。

$_SERVER['HTTP_HOST'] 是根据该请求。

因此,似乎我一个恰当使用为了让我的剧本作为兼容可能会是 $_SERVER['HTTP_HOST'].是这种假设是否正确?

后续评论:

我猜我有点偏执在读这篇文章之后,并注意到一些人所说的"他们不会相信的 $_SERVER var":

显然,讨论主要是关于 $_SERVER['PHP_SELF'] 为什么你不应该用它在形成的行动属性没有适当的逃离以防止XSS的攻击。

我的结论关于我最初的问题上,它是"安全"的使用 $_SERVER['HTTP_HOST'] 所有链接的网站上,而不必担心XSS攻击,即使用的形式。

请纠正我,如果我错误的。

有帮助吗?

解决方案

这可能是每个人的第一思想。但这一点更加困难。看看 克里斯Shiflett的文章 SERVER_NAMEHTTP_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;
}

其他提示

只是一个附加的注-如果服务器上运行,港口的其它于80(作为可能共同发展联网/内联网机)然后 HTTP_HOST 包含的港口,同时 SERVER_NAME 不。

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

(至少这是我注意到在Apache口基virtualhosts)

作为迈克已经指出下面 HTTP_HOST 含有 :443 上运行时HTTPS(除非你上运行的一个非标准的港口,这我还没有测试)。

使用。他们都是同样(在)的安全,因为在许多情况下,服务器名称只是填充HTTP_HOST无论如何。我通常去HTTP_HOST,以便用户上的确切主机名称他们开始。例如,如果我有相同的网站上。com。org域,我不想发送某人。org。com,特别是如果他们可能已登入令牌。组织结构,他们会失去,如果发送到其他领域。

不管怎样,你只需要确保webapp将只应用于已知良好的领域。这是可以做到:(a)一个应用程序的副检喜欢浓汤,或(b)通过使用虚拟机关的域名(s)你想要那个 没有响应 要求得到一个未知的主机头。

为此原因是,如果你能让你的网站被访问的下任老的名字,你把自己打开来DNS重新绑定的攻击(其中另一个网站的主机名要点你的IP,用户访问的网站的攻击者的名,然后将主机名移到攻击者的IP,把你的饼干/认证与其)和搜索引擎劫持(其中一个攻击者点自己的主机名在你的网站,并试图使搜索引擎看到它作为'最佳'主机名).

显然,讨论主要是关于$_SERVER['PHP_SELF']并为什么你不应该用它在形成的行动属性没有适当的逃离以防止XSS的攻击。

噗.那么你不应该使用 任何东西任何 属性没有逃避与 htmlspecialchars($string, ENT_QUOTES), ,所以没有什么特别的服务器变量。

这是一个详细的翻译什么解用于获得主机名称(看看第二个例子为一个更文字翻译):

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);
}

过时的:

这是我的翻译裸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);
}

它是"安全"的使用 $_SERVER['HTTP_HOST'] 所有链接的网站上,而不必担心XSS攻击,即使是在形式?

是的,这是 安全的 使用 $_SERVER['HTTP_HOST'],(甚至 $_GET$_POST) 只要你确认他们 之前接待他们。这是我做的,为安全生产服务器:

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
$reject_request = true;
if(array_key_exists('HTTP_HOST', $_SERVER)){
    $host_name = $_SERVER['HTTP_HOST'];
    // [ need to cater for `host:port` since some "buggy" SAPI(s) have been known to return the port too, see http://goo.gl/bFrbCO
    $strpos = strpos($host_name, ':');
    if($strpos !== false){
        $host_name = substr($host_name, $strpos);
    }
    // ]
    // [ for dynamic verification, replace this chunk with db/file/curl queries
    $reject_request = !array_key_exists($host_name, array(
        'a.com' => null,
        'a.a.com' => null,
        'b.com' => null,
        'b.b.com' => null
    ));
    // ]
}
if($reject_request){
    // log errors
    // display errors (optional)
    exit;
}
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
echo 'Hello World!';
// ...

优点 $_SERVER['HTTP_HOST'] 是,它的行为是更好的定义比 $_SERVER['SERVER_NAME'].对比 ➫➫:

内容主持人:头从目前的请求,如果有一个。

有:

服务器的名称主持下,目前的剧本是执行。

使用一个更好定义的界面等 $_SERVER['HTTP_HOST'] 意味着更多的SAPIs会实现它的使用 可靠的 好定义的行为。(不同 .) 然而,它仍然是完全依赖SAPI ➫➫:

没有保证每一个网络服务器将提供任何这些[$_SERVER 项];服务器可以省略一些,或者提供其他人不在此列。

要理解如何正确地检索主机名称,首先和最重要的是你需要了解服务器,它仅包含 代码 没有办法知道(预备必要的用于检验) 其自己的名字 在网络。它需要界面组件,供自己的名称。这可以通过:

  • 当地的配置文件

  • 本地数据库

  • 硬编码的源代码

  • 外部的请求(卷毛)

  • 客户机/攻击者的 Host: 请求

  • 等等

通常它通过地方(SAPI)配置文件。注意,你已经配置正确,例如在阿帕奇 ➫➫:

几件事情需要'伪造的'做的动态虚拟机看起来像一个正常的。

最重要的是服务器名称使用Apache产生自引用的网址,等等。它配置了 ServerName 指令,它可以Cgi通过 SERVER_NAME 环境变量。

实际价值在运行时使用的是 通过控制 该UseCanonicalName设置。

UseCanonicalName Off 服务器上的名字来自于内容 Host: 头在请求。 UseCanonicalName DNS 它来自一个反DNS lookup虚拟机的IP地址。前者设定用于基于名称的动态虚拟的托管,而后者是用于**基于IP的托管。

如果 Apache无法工作的服务器名称,因为没有 Host: 头或DNS lookup失败 然后 值与配置 ServerName 是用来代替。

之间的主要区别两个是 $_SERVER['SERVER_NAME'] 是一个服务器控制的变量,同时 $_SERVER['HTTP_HOST'] 是一个用户控制的价值。

该规则是永远不会信任的价值观从用户,所以 $_SERVER['SERVER_NAME'] 是更好的选择。

如浓汤指出,Apache将建立服务器名称从用户提供的数值,如果您没有设置 UseCanonicalName On.

编辑:有说所有的,如果该网站使用的名称为基础的虚拟机,HTTP主机头是唯一的方法,以达到网站的不是默认站点。

我不知道并不真的相信 $_SERVER['HTTP_HOST'] 因为它取决于头从客户。另一方面,如果一个领域要求通过客户是不是我一个,他们将不会得到我的网站,因为DNS和TCP/IP协议的指向正确的目的地。但是我不知道如果可能的劫持DNS、网络或甚至Apache server。为了安全,我定义的主机名称在环境和比较 $_SERVER['HTTP_HOST'].

添加 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(), 修改session cookie和拒绝,如果员额方法来自不同的领域。

XSS 会永远存在,甚至如果你使用 $_SERVER['HTTP_HOST'], $_SERVER['SERVER_NAME']$_SERVER['PHP_SELF']

首先,我要感谢你所有美好的回答和解释。这是方法创建基于你所有的答案,获得基址。我只有用它在非常罕见的情况。所以没有一个很大的重点放在安全问题,像XSS的攻击。也许有人需要它。

// Get base url
function getBaseUrl($array=false) {
    $protocol = "";
    $host = "";
    $port = "";
    $dir = "";  

    // Get protocol
    if(array_key_exists("HTTPS", $_SERVER) && $_SERVER["HTTPS"] != "") {
        if($_SERVER["HTTPS"] == "on") { $protocol = "https"; }
        else { $protocol = "http"; }
    } elseif(array_key_exists("REQUEST_SCHEME", $_SERVER) && $_SERVER["REQUEST_SCHEME"] != "") { $protocol = $_SERVER["REQUEST_SCHEME"]; }

    // Get host
    if(array_key_exists("HTTP_X_FORWARDED_HOST", $_SERVER) && $_SERVER["HTTP_X_FORWARDED_HOST"] != "") { $host = trim(end(explode(',', $_SERVER["HTTP_X_FORWARDED_HOST"]))); }
    elseif(array_key_exists("SERVER_NAME", $_SERVER) && $_SERVER["SERVER_NAME"] != "") { $host = $_SERVER["SERVER_NAME"]; }
    elseif(array_key_exists("HTTP_HOST", $_SERVER) && $_SERVER["HTTP_HOST"] != "") { $host = $_SERVER["HTTP_HOST"]; }
    elseif(array_key_exists("SERVER_ADDR", $_SERVER) && $_SERVER["SERVER_ADDR"] != "") { $host = $_SERVER["SERVER_ADDR"]; }
    //elseif(array_key_exists("SSL_TLS_SNI", $_SERVER) && $_SERVER["SSL_TLS_SNI"] != "") { $host = $_SERVER["SSL_TLS_SNI"]; }

    // Get port
    if(array_key_exists("SERVER_PORT", $_SERVER) && $_SERVER["SERVER_PORT"] != "") { $port = $_SERVER["SERVER_PORT"]; }
    elseif(stripos($host, ":") !== false) { $port = substr($host, (stripos($host, ":")+1)); }
    // Remove port from host
    $host = preg_replace("/:\d+$/", "", $host);

    // Get dir
    if(array_key_exists("SCRIPT_NAME", $_SERVER) && $_SERVER["SCRIPT_NAME"] != "") { $dir = $_SERVER["SCRIPT_NAME"]; }
    elseif(array_key_exists("PHP_SELF", $_SERVER) && $_SERVER["PHP_SELF"] != "") { $dir = $_SERVER["PHP_SELF"]; }
    elseif(array_key_exists("REQUEST_URI", $_SERVER) && $_SERVER["REQUEST_URI"] != "") { $dir = $_SERVER["REQUEST_URI"]; }
    // Shorten to main dir
    if(stripos($dir, "/") !== false) { $dir = substr($dir, 0, (strripos($dir, "/")+1)); }

    // Create return value
    if(!$array) {
        if($port == "80" || $port == "443" || $port == "") { $port = ""; }
        else { $port = ":".$port; } 
        return htmlspecialchars($protocol."://".$host.$port.$dir, ENT_QUOTES); 
    } else { return ["protocol" => $protocol, "host" => $host, "port" => $port, "dir" => $dir]; }
}
许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top