文件上传概述
什么是文件上传
文件上传漏洞是指由于程序员在对用户文件上传部分的控制不足或者处理缺陷,而导致的用户可以越过其本身权限向服务器上上传可执行的动态脚本文件。这里上传的文件可以是木马,病毒,恶意脚本或者WebShell等。“文件上传”本身没有问题,有问题的是文件上传后,服务器怎么处理、解释文件。如果服务器的处理逻辑做的不够安全,则会导致严重的后果
产生漏洞的原因
- 对于上传文件的后缀名(扩展名)没有做较为严格的限制
- 对于上传文件的MIMETYPE(用于描述文件的类型的一种表述方法) 没有做检查
- 权限上没有对于上传的文件目录设置不可执行权限,(尤其是对于shebang类型的文件)
- 对于web server对于上传文件或者指定目录的行为没有做限制
可能造成的危害
- 上传文件是Web脚本语言,服务器的Web容器解释并执行了用户上传的脚本,导致代码执行;
- 上传文件是Flash的策略文件crossdomain.xml,黑客用以控制Flash在该域下的行为(其他通过类似方式控制策略文件的情况类似);
- 上传文件是病毒、木马文件,黑客用以诱骗用户或者管理员下载执行:
- 上传文件是钓鱼图片或为包含了脚本的图片,在某些版本的浏览器中会被作为脚本执行,被用于钓鱼和欺诈。
将上传文件作为一个入口,溢出服务器的后台处理程序,如图片解析模块;或者上传一个合法的文本文件, 其内容包含了PHP脚本,再通过“本地文件包含漏洞(Local File Include)"执行此脚本;等等。
文件上传防护方法
前端
js类防护 利用firebug禁用js或使用burp代理工具可轻易突破。
后端(以PHP为例)
在文件被上传到服务端的时候,对于文件名的扩展名进行检查,如果不合法,则拒绝这次上传
黑名单
$is_upload = false;
$msg = null;
if (isset($_POST['submit'])) {
if (file_exists(UPLOAD_PATH)) {
$deny_ext = array('.asp','.aspx','.php','.jsp');
$file_name = trim($_FILES['upload_file']['name']);
$file_name = deldot($file_name);//删除文件名末尾的点
$file_ext = strrchr($file_name, '.');
$file_ext = strtolower($file_ext); //转换为小写
$file_ext = str_ireplace('::$DATA', '', $file_ext);//去除字符串::$DATA
$file_ext = trim($file_ext); //收尾去空
if(!in_array($file_ext, $deny_ext)) {
$temp_file = $_FILES['upload_file']['tmp_name'];
$img_path = UPLOAD_PATH.'/'.date("YmdHis").rand(1000,9999).$file_ext;
if (move_uploaded_file($temp_file,$img_path)) {
$is_upload = true;
} else {
$msg = '上传出错!';
}
} else {
$msg = '不允许上传.asp,.aspx,.php,.jsp后缀文件!';
}
} else {
$msg = UPLOAD_PATH . '文件夹不存在,请手工创建!';
}
}
白名单
$is_upload = false;
$msg = null;
if(isset($_POST['submit'])){
$ext_arr = array('jpg','png','gif');
$file_name = $_FILES['upload_file']['name'];
$temp_file = $_FILES['upload_file']['tmp_name'];
$file_ext = substr($file_name,strrpos($file_name,".")+1);
$upload_file = UPLOAD_PATH . '/' . $file_name;
if(move_uploaded_file($temp_file, $upload_file)){
if(in_array($file_ext,$ext_arr)){
$img_path = UPLOAD_PATH . '/'. rand(10, 99).date("YmdHis").".".$file_ext;
rename($upload_file, $img_path);
$is_upload = true;
}else{
$msg = "只允许上传.jpg|.png|.gif类型文件!";
unlink($upload_file);
}
}else{
$msg = '上传出错!';
}
}
检测文件幻部信息
(文件头:内容头信息 文件的16进制首部字符标识)常见文件幻部
检测数据包文件MIME类型信息
Content-Type称之为MIME信息,HTTP协议规定了上传资源的时候在Header中加上一项文件的MIMETYPE,来识别文件类型,这个动作是由浏览器完成的,服务端可以检查此类型不过这仍然是不安全的,因为HTTP header可以被发出者或者中间人任意的修改
限制Web Server对特定类型文件的行为
一般文件都是放在./upload文件夹下,只要限制该文件夹下的脚本文件处理方式
- 指定特定扩展名的文件的处理方式
- 禁止特定扩展名的文件被访问
- 只允许访问特定类型的文件
- 强制web服务器对于特定文件类型的处理
防范文件上传漏洞的方法:
- 文件上传的目录设置为不可执行
只要web容器无法解析该目录下面的文件,即使攻击者上传了脚本文件,服务器本身也不会受到影响。 - 判断文件类型
在判断文件类型时,可以结合使用MIME Type、后缀检查等方式。强烈推荐白名单方式,黑名单的方式已经无数次被证明是不可靠的。对于图片的处理,可以使用压缩函数或者resize函数,在处理图片的同时破坏图片中可能包含的HTML代码。 - 使用随机数改写文件名和文件路径
文件上传如果要执行代码,则需要用户能够访问到这个文件。在某些环境中,用户能上传,但不能访问。如果应用了随机数改写了文件名和路径,将极大地增加攻击的成本。再来就是像shell.php.rar.rar和crossdomain.xml这种文件,都将因为重命名而无法攻击。 - 单独设置文件服务器的域名
由于浏览器同源策略的关系,一系列客户端攻击将失效,比如上传crossdomain.xml、上传包含Javascript的XSS利用等问题将得到解决。 - 限制上传文件大小
主要就是防止DDOS攻击:限制上传文件的大小,防止由于内存、磁盘耗尽造成的拒绝服务。可以配置web server允许的最大Post大小。可以在代码层面获取上传文件的大小,根据文件类型的不同进行进一步的过滤。 - 确保上传文件被访问正确返回
将文件上传目录设置为静态资源目录,防止被解析为脚本执行。 使用代理页面隐藏文件真实路径。使用上述方法时,确保Content-Type与实际文件类型一致。 如果文件不允许在页面展示,仅允许下载,请设置Content-disposition:attachment。