Twitter Subscribe to PHP Blog RSS Feed Email RSS

超全局变量 $_SERVER 应用小记

添加评论 2011年3月2日
可以转载, 但必须以超链接形式标明文章原始出处和作者信息及版权声明

PHP 提供了很多有用的预定义变量,可以在执行脚本的任何位置访问,用于提供大量与环境有关的信息。可以通过这些变量获得关于当前用户会话、用户操作环境和本地操作环境等详细信息。PHP 会创建部分变量,而其他许多变量的可用性和值则取决于操作系统和 Web 服务器。

$_SERVER

$_SERVER 包含由 Web 服务器创建的信息,它提供了服务器和客户配置及其当前请求环境的有关信息。列举部分在应用程序中非常有用的变量如下:

  • $_SERVER[‘HTTP_REFERER’] 引导用户达到当前位置的页面的URL,由 user agent 设置决定。并不是所有的用户代理都会设置该项,有的还提供了修改 HTTP_REFERER 的功能。简言之,该值并不可信。
  • $_SERVER[‘HTTP_USER_AGENT’] 客户的用户代理,一般会提供操作系统和浏览器的有关信息。
  • $_SERVER[‘REMOTE_ADDR’] 客户 IP 地址。
  • $_SERVER[‘REQUEST_URI’] 客户请求的URL 的路径部分。


[code lang=”php”]
“;
echo “You are referer from “.$_SERVER[‘HTTP_REFERER’].”
“;
echo “Your IP is “.$_SERVER[‘REMOTE_ADDR’].”
“;
echo “Your request uri is “.$_SERVER[‘REQUEST_URI’].”
“;
?>
[/code]

结果显示为:

Your browser is: Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.5…Firefox/3.6.13
You are referer from http://localhost/php/variable/
Your IP is ::1
Your request uri is /php/variable/06.super_globals.php

查看本环境全部的 $_SERVER 变量可以用循环例举:
[code lang=”php”]
foreach ($_SERVER as $var => $value) {
echo “$var => $value
“;
}
[/code]
当然你也可以使用调试函数 var_dump() 来展示 $_SERVER 这个数组:
[code lang=”php”]
var_dump($_SERVER);
[/code]
详细说明请参考 http://www.php.net/manual/zh/reserved.variables.server.php

这些信息被大量地用于站点流量来源的统计系统中,然而,有些信息未必十分准确,因为某一些信息可以被删除或者伪造的。例如下面我们用 PHP 的 fsockopen() 函数来对远程站点建立一个 socket 连接,并伪造http referer。

伪造 HTTP_REFERER

[code lang=”php”]

[/code]
假设 example.com 里面有个纯粹地依靠 $_SERVER[‘HTTP_REFERER’] 来统计进站统计的系统,那么这里就会产生一条记录,访问者通过 http://phpstone.com 到达了 http://www.example.com 这个页面,而实际情况并不是这样。当然,socket 连接的方式对于使用 javascript 的统计页面并不会产生影响,例如 google analytics。

关于使用 head() 函数跳转的 referer 问题

另外一个值得注意的是,在 PHP 的脚本页面如果使用 head(“Location:http://www.example.com”) ,本页面本身是不能作为 referer 的,因为所谓的“引导”页面指的是浏览器的引导,而不是后台脚本的重定向。如果你要使用当前脚本页面作为 referer ,可用的办法是使用 javascript 自动执行表单来达到:
[code lang=”javascript”]




[/code]
注:这只是一个示例,实际操作中复杂环境可能会产生一些问题,但是通过其他的对应方法应该可以得到解决。

慎用 $_SERVER[‘PHP_SELF’]

很多使用 $_SERVER[‘PHP_SELF’] 来执行表单的动作为代码页本身,请看下面表单操作:
[code lang=”php”]
“;
echo $_SERVER[‘PHP_SELF’].”
“;
echo $_SERVER[‘SCRIPT_NAME’].”
“;
echo $_SERVER[‘REQUEST_URI’];
}
?>



[/code]
表面上看,’PHP_SELF’ 似乎没有什么问题,在我的环境返回的结果如下:

Greetings, test, and welcome.
/php/variable/05._POST.php
/php/variable/05._POST.php
/php/variable/05._POST.php

测试环境的文件路径是,http://localhost/php/variable/05._POST.php ,现在我们在访问路径后面加个”/get”运行的结果如下:

Greetings, test, and welcome.
/php/variable/05._POST.php/get
/php/variable/05._POST.php
/php/variable/05._POST.php/get

查看 HTML 源码,可以看到 “<form action=”/php/variable/05._POST.php/get”…”字段,也就是说,$_SERVER[‘PHP_SELF’] 是可以随着用户输入附加内容而发生改变的,这就可以给攻击者提供便利条件。因此在表单提交里,还是尽量使用 $_SERVER[‘SCRIPT_NAME’] 。

至于 $_SERVER[‘REQUEST_URI’] ,是完全显示用户输入请求的。假设输入访问 http://www.example.com ,example.com 默认展示的页面是 index.php 那么 ‘HTTP_SELF’ 的内容是 “/index.php”,而 ‘REQUEST_URI’ 的内容是 “ / ”,因为用户请求的是 “ / ”。

PS: 在 PHP5 版本中,我发现即使 php.ini 中设置了 register_globals = Off ,在表单提交里使用 <?php  $PHP_SELF; ?> 这个老语法代码仍然正常,只有在使用<?php  echo $PHP_SELF; ?> 时才会提示未定义的变量,不知道是不是 PHP 的 Bug。

评论

  1. 素衣

    呵呵,最近也在研究这个,请问博主,可不可以伪造来源,然后跳转到另外一个网页 ?比如我打开一个文件,然后自动跳转到baidu,而且baidu显示的来源是我设定的。请教。。

  2. frePerl

    对于用户使用浏览器在站点间的正常跳转,目前我也不清楚有什么方法可以伪造来源,因此没有写入文章。