文件上传漏洞等危害
攻击者上传shell脚本,借助脚本控制服务器,随意执行命令。
漏洞举例
<?php
$dir = 'uploads/';
$file = $dir . basename($_FILES['file']['name']);
move_upload_file( $_FILE['file']['tmp_name'], $file);
?>
如果攻击者上传如脚本文件file.php
<?php
system($_GET['shell']);
?>
则可以通过http://host/uploads/file.php?shell=ls -la,查看服务器目录信息,并且可以执行任何shell命令。
过滤上传文件类型和文件扩展名
<?php
if( $_FILEs['file']['type'] != 'image/gif' ){
die('类型错误');
}
?>
但是如果攻击者通过修改POST数据包中的Content-Type:text/plain字段为Content-Type:image/git,则可跳过检验成功上传,所以还需检查文件扩展名。
<?php
$whiteList = [
'.jpg', '.gif', '.png', '.jpeg',
];
$ext = substr( $_FILES['file']['name'], -4 );
if( !in_array( $ext, $whiteList ) ){
die('类型错误');
}
?>
综合防护
- 白名单限制文件类型
- 白名单限制文件扩展名
- 随机文件名
- 上传目录放到项目可执行目录之外
- 禁止上传文件的执行权限
- 如果可以的话,通过php.ini配置禁用危险函数: disable_function = system,exec,scandir,shell_exec等
<?php
class FileSecurity
{
const DIR = '/data/uploads/';
private $whiteExt = [
'.jpg', '.gif', '.png', '.jpeg',
];
private $whiteType = [
'image/jpg', 'image/gif', 'image/png', 'image/jpeg',
];
private $nameChars = [
'a', 'b', 'c', 'd', 'e', 'f', 'g',
'h', 'i', 'j', 'k', 'l', 'm', 'n',
'o', 'p', 'q', 'r', 's', 't', 'u',
'v', 'w', 'x', 'y', 'z',
'A', 'B', 'C', 'D', 'E', 'F', 'G',
'H', 'I', 'J', 'K', 'L', 'M', 'N',
'O', 'P', 'Q', 'R', 'S', 'T', 'U',
'V', 'W', 'X', 'Y', 'Z',
'1', '2', '3', '4', '5', '6', '7', '8', '9', '0',
];
public function filter($file, $type)
{
if ( !in_array($type, $this->whiteType) ){
return false;
}
$ext = substr($file, -4);
if ( !in_array($ext, $this->whiteExt) ){
return false;
}
}
public function getFileName()
{
$len = count($this->nameChars) - 1;
shuffle($this->nameChars);
$name = '';
for ($i = 0; $i < $len; $i++){
$name .= $this->nameChars[ mt_rand(0, $len) ];
}
return $name;
}
public function chmod($file)
{
$file = self::DIR . $file;
@chmod($file, 0444);
}
}
?>