文件上传验证

原理概述

应用程序因为业务需要,提供了上传文件的功能,但是在上传点处对所上传的文件安全检查不够严格甚至不做检查,导致黑客可以上传任意文件,进而获取网站控制权甚至是服务器控制权。

危害

1.上传的文件若为web脚本文件,服务器的web容器解释并执行了黑客上传的脚本,导致黑客直接获取网站控制权
2.上传文件为crossdomain.xml,则黑客能控制flash在该域下的行为
3.上传文件为病毒,木马等,黑客可以诱骗用户或者管理员下载执行
···


总结一下: 文件上传后会在/tmp/目录下存放临时文件tmp_name, 本次请求结束后,此临时文件立即删除(因此一般无法正常查看),需要重新命名到/tmp目录下或者其他目录下

BadCase样例

BadCase样例1:

 
 
  1. /**
  2. 对上传的文件不做任何检查,黑客可以直接上传任意文件,最常见的利用方式就是上传一个具有文件
  3. 操作功能的脚本,直接获得网站控制权
  4. **/
  5. if($_FILES)
  6. {
  7. $dest="./upfilestore/";
  8. move_uploaded_file($_FILES['upfile']['tmp_name'],$dest.$_FILES['upfile']['name']);
  9. }

BadCase样例2:

 
 
  1. /**
  2. 本例看似对上传的文件做了类型检查,非图片类型的则不允许上传
  3. $file['type']是从客户端获取而来的数据,黑客可以将数据包截获下来更改http header中
  4. content-type的值来绕过检查
  5. **/
  6. $dest="./upfilestore/";
  7. $uptypes=array(
  8. 'image/jpg',
  9. 'image/jpeg',
  10. 'image/png',
  11. 'image/gif'
  12. );
  13. $file=$_FILES['upfile'];
  14. if(!in_array($file['type'],$uptypes))
  15. {
  16. die("invalid types!");
  17. }
  18. else
  19. {
  20. move_uploaded_file($file['tmp_name'],$dest.$file['name']);
  21. }

BadCase样例3:

 
 
  1. /**
  2. 本例使用了黑名单来检查上传的文件名后缀,如果是黑名单中的类型则禁止上传
  3. 但是黑名单是一种很不好的思想,存在被绕过的风险
  4. 本例中黑客可以上传xxx.php4,xxx.php3,xxx.asa,xxx.pl等类型的文件都可以绕过检查
  5. **/
  6. function getExt($filename)
  7. {
  8. return substr($filename,strripos($filename,".")+1);
  9. }
  10. $disAllowExt=array('php','asp','aspx','jsp','exe');
  11. $fileExt=strtolower(getExt($_FILES['upfile']['name']));
  12. if(in_array($fileExt,$disAllowExt))
  13. {
  14. die("disallowed type");
  15. }
  16. else
  17. {
  18. $dest="./upfilestore/";
  19. move_uploaded_file($_FILES['upfile']['tmp_name'],$dest.$_FILES['upfile']['name']);
  20. }

BadCase样例4

 
 
  1. /**
  2. 在PHP版本<5.3.4并且magic_quotes_gpc=off的情况下,即使是使用白名单检测文件名后缀也是
  3. 存在被绕过的风险的
  4. 黑客可以提交hack.php\0.jpg, 其中\0代表0x00,这样能绕过文件名后缀的检查,也能由于0x00
  5. 截断作用使得最终保存在服务器上的为hack.php
  6. 本例中黑客可以提交file=hack.php%00,然后上传一个后缀为jpg的文件,最终生成的就是hack.php文件
  7. **/
  8. error_reporting(0);
  9. if(isset($_FILES))
  10. {
  11. $ext_arr = array('flv','swf','mp3','mp4','3gp','zip','rar','gif','jpg','png','bmp');
  12. $file_ext = substr($_FILES['upfile']['name'],strrpos($_FILES['upfile']['name'],".")+1);
  13. if(in_array($file_ext,$ext_arr))
  14. {
  15. $tempFile = $_FILES['upfile']['tmp_name'];
  16. $targetPath = $_SERVER['DOCUMENT_ROOT'].$_REQUEST['file'].rand(10, 99).date("YmdHis").".".$file_ext;
  17. if(move_uploaded_file($tempFile,$targetPath))
  18. {
  19. echo 'upload success'.'<br>';
  20. }
  21. else
  22. {
  23. echo("upload failed!");
  24. }
  25. }
  26. else
  27. {
  28. echo("upload failed");
  29. }
  30. }

修复建议

1.对于上传的文件,一定要做文件类型检查,且一定要在服务端做检查,如果只在前端用JS检查则完全可以被绕过
2.上传之后的文件,需要对文件重命名为一个随机文件名
3.如果PHP版本小于5.3.4则需要对上传的文件名进行转义,防止被截断上传

样例如下:

 
 
  1. $file=$_FILES['upfile'];
  2. //检查PHP版本,如果小于5.3.4则要检查magic_quotes_gpc选项的值,如果该值关闭,则要对上传
  3. //的文件名转义
  4. if(PHP_VERSION<'5.3.4')
  5. {
  6. if(!ini_get('magic_quotes_gpc'))
  7. {
  8. $file['name']=addslashes($file['name']);
  9. }
  10. }
  11. //白名单控制允许上传的文件名后缀
  12. $allowedExt=array('jpg','gif','jpeg','pdf');
  13. $fileExt=pathinfo($file['name'],PATHINFO_EXTENSTION);
  14. if(!in_array($fileExt,$allowedExt))
  15. {
  16. die('disallowed type');
  17. }
  18. else
  19. {
  20. $dest='./upfilestore/';
  21. //将文件重命名一个随机文件名
  22. $filename=md5(rand()).date("YmdHis").$fileExt;
  23. move_uploaded_file($file['tmp_name'],$dest.$filename);
  24. }

4.如果只允许上传图片类型的文件,那么可以使用PHP的GD库对上传的文件的内容做二次渲染,从而可以剔除文件内容中非图片的数据,防止黑客在正常图片中注入恶意代码
样例如下:
首先需要在PHP.ini中设置启用GD库的扩展,找到extension=php_gd2.dll将其前面的分号(;)去掉即可

 
 
  1. ; Windows Extensions
  2. ; Note that ODBC support is built in, so no dll is needed for it.
  3. ; Note that many DLL files are located in the extensions/ (PHP 4) ext/ (PHP 5)
  4. ; extension folders as well as the separate PECL DLL download (PHP 5).
  5. ; Be sure to appropriately set the extension_dir directive.
  6. ;
  7. ;extension=php_bz2.dll
  8. extension=php_curl.dll
  9. ;extension=php_fileinfo.dll
  10. extension=php_gd2.dll

代码如下:

 
 
  1. $file=$_FILES['upfile'];
  2. $dest='./upfilestore/'; //存放上传文件的路径,各产品线根据自己的实际情况进行设置
  3. //检查PHP版本,如果小于5.3.4则要检查magic_quotes_gpc选项的值,如果该值关闭,则要对上传
  4. //的文件名转义
  5. if(PHP_VERSION<'5.3.4')
  6. {
  7. if(!ini_get('magic_quotes_gpc'))
  8. {
  9. $file['name']=addslashes($file['name']);
  10. }
  11. }
  12. //白名单控制允许上传的文件名后缀,这里只允许上传图片
  13. $allowedExt=array('jpg','gif','jpeg');
  14. $fileExt=pathinfo($file['name'],PATHINFO_EXTENSTION);
  15. if(!in_array($fileExt,$allowedExt))
  16. {
  17. die('disallowed type');
  18. }
  19. else
  20. {
  21. if($fileExt=='jpg'||$fileExt=='jpeg')
  22. {
  23. $ext='jpeg';
  24. }
  25. else
  26. {
  27. $ext='gif';
  28. }
  29. //重新渲染图片内容,这里默认采用原始大小,因此不做截取操作,各产品线可根据需要自行截取大小
  30. $createFun='imagecreatefrom'.$ext;
  31. $newimageFun='image'.$ext;
  32. $im=$createFun($file['tmp_name']);
  33. //给文件重命名一个随机文件名
  34. $filename=md5(rand()).date("YmdHis").$ext;
  35. //保存文件到指定位置
  36. $newimageFun($im,$dest.$filename);
  37. //释放内存
  38. imagedestroy($im);
  39. }
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值