PHP$_SERVER['HTTP_HOST']与$_SERVER['SERVER_NAME'],我了解男人的网页是否正确?
题
我做了很多的搜索和阅读PHP $_SERVER文档.我有这个权利对于其使用对于我PHP scripts为简单的链接使用的定义在我的网站?
$_SERVER['SERVER_NAME']
是根据你的网服务器的配置文件(Apache2在我的情况),并且根据一些指示:(1)虚拟主机,(2)服务器名称,(3)UseCanonicalName,等等。
$_SERVER['HTTP_HOST']
是根据该请求。
因此,似乎我一个恰当使用为了让我的剧本作为兼容可能会是 $_SERVER['HTTP_HOST']
.是这种假设是否正确?
后续评论:
我猜我有点偏执在读这篇文章之后,并注意到一些人所说的"他们不会相信的 $_SERVER
var":
http://markjaquith.wordpress.com/2009/09/21/php-server-vars-not-safe-in-forms-or-links/
http://php.net/manual/en/reserved.variables.server.php#89567 (注释:弗拉基米尔*Kornea14-Mar-2009年01:06)
显然,讨论主要是关于 $_SERVER['PHP_SELF']
为什么你不应该用它在形成的行动属性没有适当的逃离以防止XSS的攻击。
我的结论关于我最初的问题上,它是"安全"的使用 $_SERVER['HTTP_HOST']
所有链接的网站上,而不必担心XSS攻击,即使用的形式。
请纠正我,如果我错误的。
解决方案
这可能是每个人的第一思想。但这一点更加困难。看看 克里斯Shiflett的文章 SERVER_NAME
与 HTTP_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]; }
}