当前位置:  开发笔记 > 编程语言 > 正文

PHP $ _SERVER ['HTTP_HOST']与$ _SERVER ['SERVER_NAME'],我是否正确理解了手册页?

如何解决《PHP$_SERVER['HTTP_HOST']与$_SERVER['SERVER_NAME'],我是否正确理解了手册页?》经验,为你挑选了6个好方法。

我做了很多搜索,还阅读了PHP $ _SERVER文档.对于在我的网站中使用的简单链接定义,我的PHP脚本使用哪个权限?

$_SERVER['SERVER_NAME'] 是基于您的Web服务器的配置文件(在我的情况下是Apache2),并根据一些指令而变化:(1)VirtualHost,(2)ServerName,(3)UseCanonicalName等.

$_SERVER['HTTP_HOST'] 基于客户的要求.

因此,在我看来,为了使我的脚本尽可能兼容而使用的正确方法是$_SERVER['HTTP_HOST'].这个假设是否正确?

后续评论:

我想在读完这篇文章之后我有点偏执,并注意到有些人说"他们不会相信任何一个$_SERVER变种":

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(评论:Vladimir Kornea 14-Mar-2009 01:06)

显然,讨论主要是关于$_SERVER['PHP_SELF']为什么你不应该在表单action属性中使用它而没有适当的转义以防止XSS攻击.

我对上述原始问题的结论是$_SERVER['HTTP_HOST'],即使在表单中使用,也可以"安全"地使用网站上的所有链接,而不必担心XSS攻击.

如果我错了,请纠正我.



1> Gumbo..:

这可能是每个人的第一个想法.但这有点困难.请参阅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;
}


大声笑,我读了那篇文章,它似乎没有回答我的问题.专业开发人员使用哪一个?如果是.
Iiiiinteresting,我从来不知道SERVER_NAME在Apache中默认使用了用户提供的值.

2> Simon East..:

只是另外一个注意事项 - 如果服务器在80以外的端口上运行(在开发/内联网机器上可能是常见的),则HTTP_HOST包含端口,而不包含端口SERVER_NAME.

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

(至少这是我在基于Apache端口的虚拟主机中注意到的)

正如迈克下面提到的,HTTP_HOST没有包含:443在HTTPS运行时(除非你是一个非标准端口,我没有测试运行).


注意:该端口在443的HTTP_HOST中也不存在(默认SSL端口).

3> bobince..:

使用其中之一 它们同样(安全),因为在许多情况下,SERVER_NAME只是从HTTP_HOST填充.我通常会使用HTTP_HOST,以便用户保持他们开始的确切主机名.例如,如果我在.com和.org域中拥有相同的站点,我不想将.org中的某人发送到.com,特别是如果他们可能在.org上有登录令牌,那么如果他们被发送到另一个域名.

无论哪种方式,您只需要确保您的webapp只会响应已知良好的域名.这可以通过以下方式完成:(a)使用Gumbo的应用程序端检查,或者(b)使用您想要的域名上的虚拟主机,该主机不响应给出未知主机头的请求.

这样做的原因是,如果您允许以任何旧名称访问您的站点,您可以对DNS重新绑定攻击(其他站点的主机名指向您的IP,用户使用攻击者的主机名访问您的站点,然后是主机名)移动到攻击者的IP,带上你的cookie/auth)和搜索引擎劫持(攻击者在你的站点指出他们自己的主机名,并试图让搜索引擎将其视为'最佳'主要主机名).

显然,讨论主要是关于$ _SERVER ['PHP_SELF']以及为什么你不应该在表单action属性中使用它而没有适当的转义以防止XSS攻击.

Pfft.好吧,你不应该在任何属性中使用任何东西而不用转义,所以那里的服务器变量并没有什么特别之处.htmlspecialchars($string, ENT_QUOTES)


谷歌肯定有(并且可能仍然有某种形式)欺骗网站的概念,所以如果你的网站可以访问`http:// example.com /`,http:// www.example.com /`和`http:// 93.184.216.34 /`它会将它们合并到一个站点中,选择最流行的地址,并只返回该版本的链接.如果您可以将"evil-example.com"指向同一地址并让Google简要地将其视为更受欢迎的地址,您可以窃取该网站的果汁.我不知道今天有多实用,但我看到俄罗斯链接农场攻击者过去曾尝试这样做.

4> antitoxic..:

这是Symfony用于获取主机名的详细翻译(请参阅第二个示例以获得更直接的翻译):

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


看起来很好.那些是[三元运算符](http://php.net/manual/en/language.operators.comparison.php#language.operators.comparison.ternary),实际上可以节省时间(和字节)而不会降低可读性,当使用时适当.

5> Pacerier..:

是否"安全" $_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']意味着更多的SAPI将使用可靠的明确定义的行为来实现它.(不像其他的.)但是,它仍然是完全依赖于SAPI ➫➫:

无法保证每个Web服务器都能提供任何这些[ $_SERVER条目]; 服务器可以省略一些,或提供此处未列出的其他服务器.

要了解如何正确检索主机名,首先您需要了解只包含代码的服务器无法知道(验证的先决条件)网络上自己的名称.它需要与为其提供自己名称的组件进行交互.这可以通过以下方式完成:

本地配置文件

本地数据库

硬编码的源代码

外部请求(卷曲)

客户/攻击者的Host:请求

等等

通常通过本地(SAPI)配置文件完成.请注意,您已正确配置它,例如在Apache➫➫中:

需要"伪造"一些东西才能使动态虚拟主机看起来像普通的虚拟主机.

最重要的是Apache用于生成自引用URL等的服务器名称.它使用该ServerName指令进行配置,并通过SERVER_NAME环境变量提供给CGI .

运行时使用的实际值 UseCanonicalName设置控制.

随着 UseCanonicalName Off服务器的名字来自内容Host:的请求头.有了 UseCanonicalName DNS它来自虚拟主机的IP地址的反向DNS查找.前一个设置用于基于名称的动态虚拟主机,后者用于基于IP的主机托管.

如果因为没有Apache可以不工作了服务器名Host:头或DNS查找失败与配置的值ServerName来代替.



6> Powerlord..:

两者之间的主要区别在于它$_SERVER['SERVER_NAME']是服务器控制的变量,$_SERVER['HTTP_HOST']而是用户控制的值.

经验法则是永远不要相信用户的价值观,因此这$_SERVER['SERVER_NAME']是更好的选择.

正如Gumbo所指出的,如果你没有设置,Apache将根据用户提供的值构建SERVER_NAME UseCanonicalName On.

编辑:说了这么多,如果该站点使用的是基于名称的虚拟主机,则HTTP Host标头是访问非默认站点的站点的唯一方法.


用户可以更改它,因为它只是来自传入请求的Host头的内容.主服务器(或绑定到__default __:80的VirtualHost)将响应所有未知主机,因此该站点上的Host标记的内容可以设置为任何内容.
请注意,基于IP的虚拟主机将始终响应其特定的IP,因此您无法在任何情况下**信任它们上的HTTP主机值.
推荐阅读
爱唱歌的郭少文_
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有