一、背景
突然想起来之前面试的一些面试题,让我写出几个服务器变量$SERVER代表的意思。。实话实说,这些东西已经忘记很久了,都是用的时候直接上网查,今天再复习复习吧。
二、$SERVER
$_SERVER 是一个包含诸如头信息(header)、路径(path)和脚本位置(script locations)的数组。它是 PHP 中一个超级全局变量,我们可以在 PHP 程序的任何地方直接访问它。
1、$SERVER包含的参数
#测试网址: http://localhost/blog/testurl.php?id=5
//获取域名或主机地址
echo $_SERVER['HTTP_HOST']."<br>"; #localhost
//获取网页地址
echo $_SERVER['PHP_SELF']."<br>"; #/blog/testurl.php
//获取网址参数
echo $_SERVER["QUERY_STRING"]."<br>"; #id=5
//获取用户代理
echo $_SERVER['HTTP_REFERER']."<br>";
//获取完整的url
echo 'http://'.$_SERVER['HTTP_HOST'].$_SERVER['REQUEST_URI'];
echo 'http://'.$_SERVER['HTTP_HOST'].$_SERVER['PHP_SELF'].'?'.$_SERVER['QUERY_STRING'];
#http://localhost/blog/testurl.php?id=5
//包含端口号的完整url
echo 'http://'.$_SERVER['SERVER_NAME'].':'.$_SERVER["SERVER_PORT"].$_SERVER["REQUEST_URI"];
#http://localhost:80/blog/testurl.php?id=5
//只取路径
$url='http://'.$_SERVER['SERVER_NAME'].$_SERVER["REQUEST_URI"];
echo dirname($url);
#http://localhost/blog
//其他的
$_SERVER['REQUEST_URI']:访问此页面所需的 URI 。
$_SERVER['SCRIPT_FILENAME']:当前运行 PHP 程序的绝对路径及文件名。
$_SERVER['argv']:传递给当前 PHP 程序的参数。
以上是一些常用的$SERVER数组。
2、关于 $SERVER[HTTP_HOST]
和$SERVER[SERVER_NAME ]
的区别
这部分具体参考链接:
php $_SERVER中的SERVER_NAME 和HTTP_HOST的区别
当满足以下三个条件时,两者会输出相同信息。
1. 服务器为80端口
2. apache的conf中ServerName设置正确
3. HTTP/1.1协议规范
建议使用$SERVER[‘HTTP_POST’]比较稳定一些
3、关于$_SERVER["REQUEST_URI"]
之前在网上经常会遇到使用$_SERVER[“REQUEST_URI”] 取不到值的情况,后面才知道,这个变量只有 apache 才支持,如果你使用的是nginx或者其他服务器,需要用其他方式获得
<?php
// 说明:获取 _SERVER['REQUEST_URI'] 值的通用解决方案
// 来源:drupal-5.1 bootstrap.inc
// 整理:CodeBit.cn ( http://www.CodeBit.cn )
function request_uri()
{
if (isset($_SERVER['REQUEST_URI']))
{
$uri = $_SERVER['REQUEST_URI'];
}
else
{
if (isset($_SERVER['argv']))
{
$uri = $_SERVER['PHP_SELF'] .'?'.$_SERVER['argv'][0];
}
else
{
$uri = $_SERVER['PHP_SELF'] .'?'.$_SERVER['QUERY_STRING'];
}
}
return $uri;
}
?>
三、关于PHP的$_SERVER[‘PHP_SELF’]造成的XSS漏洞攻击及其解决方案
参考链接:
PHP的$_SERVER[‘PHP_SELF’]造成的XSS漏洞攻击及其解决方案
这部分,笔者建议:
1、htmlentities
用htmlentities($_SERVER['PHP_SELF'])
来替代简单的$_SERVER[‘PHP_SELF’],这样即使网址中包含恶意代码,也会被“转换”为用于显示的html代码,而不是被直接嵌入html代码中执行,简单一点说,就是“<”会变成“<”,变成无害的了。
2、REQUEST_URI
用$_SERVER["REQUEST_URI"]
来替代$_SERVER[‘PHP_SELF’],在phpinfo()中可以看到这两个变量的区别:
$_SERVER[”REQUEST_URI”] : /fwolf/temp/test.php/%22%3E%3Cscript%3Ealert(’xss’)%3C/script%3E%3Cfoo
$_SERVER[”PHP_SELF”] : /fwolf/temp/test.php/”>
$_SERVER["REQUEST_URI"]会原封不动的反映网址本身,网址中如果有%3C,那么你得到的也将会是%3C,而$ _SERVER['PHP_SELF']会对网址进行一次urldecode操作,网址中的%3C将会变成字符“<”,所以就产生了漏洞。
需要注意的是,在很多情况下,浏览器会对用户输入要提交给web服务器的内容进行encode,然后服务器端程序会自动进行decode,得到相应的原指,在我们进行post或者get操作的时候都是这样。
end
===============================================================
20180626补充:
php的$server['HTTP_ORIGIN']
这个参数在出现跨域请求的情况下,会返回请求的域名
我们可以在限制跨域请求的时候,使用该方法,获取访问的域名,如果该域名在我们的允许名单里,则生成一个新的header头
代码如下:
$allow_origin = array(
'http://pzhiliao.local',
'http://miaozhiliao.com',
'http://lux.xzhiliao.com/',
'http://svzhiliao.com/',
'http://www.xl.com/',
'http://appb.xzl.com:8080',
'http://appeb.xl.com',
'http://xu.apweb.xl.com',
);
//判断是否存在跨域,获取请求的域名
$origin = isset($_SERVER['HTTP_ORIGIN'])? $_SERVER['HTTP_ORIGIN'] : '';
//如果得到的域名在我们的array之内的话,则加个header头,解决跨域问题
if(in_array($origin, $allow_origin)){
header("Access-Control-Allow-Origin:".$origin);
}