复习PHP表单时,在教程中看到这个问题,然后了解一下。
介绍一下这个问题
先来说说这个超级全局变量吧
其实我觉得这个变量还蛮有意思的。
$_SERVER[“PHP_SELF”]是超级全局变量,返回当前正在执行脚本的文件名,与 document root相关。
所谓 document root 就是apache服务器网页(文档)根目录
既然说到这个,那就补充一个知识点1
2
3
4
5
6
7
8
9
10
11documentroot 和directory的区别:
1.DocumentRoot
DocumentRoot指定apache服务器网页(文档)根目录
DocumentRoot "/home/iflow/apache2/htdocs"
它的作用是指定网站文件在服务器存放路径。
2..Directory
Directory是在只指定目录的情况下默认显示的文件名
Directory home.html index.html index.html.var index.shtml
作用是我打开网站时,输入 域名或者url+目录,如果目录下存在DirectoryIndex设置的文件名的文档,home.html index.html 等,默认就打开这样的文件。没有这些文档的话,打开存在的目录会显示Forbidden错误。
$_SERVER[‘PHP_SELF’],它的值是“当前php文件相对于网站根目录的位置地址”。
也就是说,如果在http://www.xxxx.com/output/html/data.php中 使用$_SERVER[‘PHP_SELF’]
代码如下:1
echo $_SERVER['PHP_SELF'];
那么返回的内容就是1
/output/html/data.php
那也就是说,一般情况下,我们通过什么地址访问某网站,就会返回什么样的document root。1
2<form action="<?php echo $_SERVER[’PHP_SELF’]; ?>">
<input type="submit" name="submit" value="submit"/>
这么一段代码,看着没什么问题,本来看来这段代码其实是挺方便的,对于调用代码。
如果我们访问 http://…/test.php/a=1
那么我们将得到如下的客户端代码:
(假如该代码所在页面是http://www.shuihan.com/form.php )1
2<form action="/fwolf/temp/test.php/a=1">
<input type="submit" name="submit" value="submit"/> </form>
那么这时候如果我们使用XSS跨站攻击。
我们访问 http://www.shuihan.com/form.php%22%3E%3Cscript%3Ealert(‘XSS attack!’)%3C/script%3E%3Cbr
那么实际上客户端代码为:1
2
3
4
5<form method="post" action="http://www.shuihan.com/form.php">
<script>alert('XSS attack!')</script><br /><br><!-- My Form -->
</form>
一次XSS攻击完成。
如何修复
方法一
$_SERVER[“PHP_SELF”] 可以通过 htmlspecialchars() 函数来避免被利用。
form 代码如下所示:1
<form method="post" action="<?php echo htmlspecialchars($_SERVER["PHP_SELF"]);?>">
htmlspecialchars() 把一些预定义的字符转换为 HTML 实体。现在如果用户想利用 PHP_SELF 变量, 结果将输出如下所示:1
<form method="post" action="test_form.php/"><script>alert('hacked')</script>">
这样即使网址中包含恶意代码,也会被“转换”为用于显示的html代码,而不是被直接嵌入html代码中执行,简单一点说,就是”<”会变成”<”,变成无害的了。
方法二
用$_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操作的时候都是这样。
另外还有两点需要指出,第一是这种写法虽然没有直接用到$_SERVER[‘PHP_SELF’],但实际效果却是一样的,只是发生的时间错后到了用户提交之后的下一个页面,所以,form的action还是不要留空的好。第二点,除了PHP_SELF之外,其他的$_SERVER变量也许也会有类似的漏洞,比如SCRIPT_URI, SCRIPT_URL, QUERY_STRING, PATH_INFO, PATH_TRANSLATED等等,在使用他们之前一定要先作htmlentities之类的
FILE和$_SERVER[“PHP_SELF”]的区别
1 | _FILE_:a文件include b文件,在b文件中echo __FILE__,显示的是b的路径 |