恶意上传的文件

时间:2015-12-18 04:26:08

标签: php file-upload upload

我读了一些关于上传文件的文章,人们可以上传恶意程序(php,exe,...)来攻击服务器和网站,最安全的保护方式是什么,避免对网站和服务器造成任何危险,这是我正在使用的一个类,如果要添加任何内容,请告诉我(禁用clamav扫描,扫描文件需要时间):

<html xmlns="http://www.w3.org/1999/xhtml" dir="rtl">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />  
</head>

<body>
<?php

final class uploadFiles {

// params
private $uErrors=array(), $aErrors=array(), $dErrors=array();

/*
 # uErrors = Show errors to the user
 # aErrors = Show errors to the admin ONLY
 # dErrors = Send delete file error to admin
 */

// get user group, level and id
public function __construct($fileField) {

    $fileName     = basename($_FILES['fileName']['name']); // get file name

    $this->fileName     = trim($fileName);
    $this->fileField    = $fileField;

    # extract file info

    // get file name before the dot sign
    //$info       = pathinfo($this->fileName);
    //$fileInit   = basename($this->fileName,'.'.$info['extension']);

    $this->fileTmp      = $_FILES[$this->fileField]['tmp_name']; // get temp name
    $this->fileSize     = basename($_FILES[$this->fileField]['size']); // get file size
    $this->fileType     = basename($_FILES[$this->fileField]['type']); // get file type
    $this->fileError    = basename($_FILES[$this->fileField]['error']); // list error codes
    //$this->fileInit     = $fileInit;

    } // end function __construct

// check if file_uploads is set to ON or OFF
public final function checkUploads() {

    if(ini_get('file_uploads')){   
        return true;
        } 
        return false;
} // end checkUploads


// get file extension
public final function getFileExt() {

    $getInfo = pathinfo($this->fileName);
    $fileExt = basename($getInfo['extension']);
    $fileExt = strtolower($fileExt);

    $this->fileExt  = $fileExt;


    return $this->fileExt;
} // end getFileExt


// allowed file extensions
public final function allowedFileExt($extArray=array()) {       

    $this->extArray = $extArray;

    $authExtList    = implode(' ،',$this->extArray);

    $this->authExtList = $authExtList;

    if((in_array($this->getFileExt(), $this->extArray)) && (!empty($this->fileName)))
    {
        return true;
    }
        $this->uErrors[] = 'إمتداد الملف غير مقبول، المرجو إختيار أحد الإمتدادات التالية: '.$this->authExtList;
        return false;
} // end allowedFileExt


// allowed file size
public final function allowedFileSize($maxFileSize) {       

    $this->maxFileSize = $maxFileSize;

    if($this->fileSize > $this->maxFileSize) 
    {
        $this->uErrors[] = 'حجم الملف كبير جدا';
        return false;
    } 
        return true;
} // end allowedFileSize


// create a new folder
public final function newDir($dirname) {

    $this->dirname  = $dirname;

    // check if the directory exists or not
    if(is_dir($this->dirname))
    {
        // if exists, check whether is writable or not
        if(!is_writable($this->dirname)) {
            // NB: You need to have enough permissions to perform this action
            // set proper chmod, DO NOT user umask
            if(chmod($this->dirname, 0755)) { // change the chmod to 755
             return true;
        } else {
            //$this->uErrors[] = 'ليس لديك صلاحيات كافية لتغيير صلاحيات المجلد';
            return false;
        }
        } // end is_writable

        return true;
    } else {

        // if not, create it with 755 persmission
        // NB: You need to have enough permissions to perform this action
        if(mkdir($this->dirname, 0755))
        {
            return true;
        }
            //$this->uErrors[] = 'لا تملك الصلاحيات الكافية ﻹنشاء مجلد جديد';
            return false; // in case of not enough permission
    } // end is_dir

        return false;

} // end newDir


/*
# Scanning file from any malware / virus using Clamav (Clam Anti Virus)
# Works with Ubuntu ==> sudo apt-get install clamav
*/
public final function scanFile(){

    //$safe_path = escapeshellarg($this->fileTmp);
    $safe_path = escapeshellarg($this->dirname.'/'.$this->fileName);
    $cmd = '/usr/bin/clamscan  2>&1' . $safe_path;
    $result = $cmd;
    //echo $result.'<br />';
    $out = '';
    $int = -1;
    $return = exec($cmd, $out, $int);

    // if a malware / virus found
    if ($int != 0) 
    {
        return true;
    }   
        return false;

}


// delete file if a virus / malware found
public final function delFile(){

    // if true 
    //if($this->scanFile()){
        /*
        $this->uErrors[] = 'لم نتمكن من رفع الملف، المرجو المحاولة لاحقا';

        // get current URL
        $curURL = $_SERVER['REQUEST_URI'];

        // refresh after 5 secs
        //echo '<meta http-equiv="refresh" content="5; '.$curURL.'" />';
        */
        $delFile = unlink($this->fileTmp); // Delete the file
        if($delFile)
        {
            return true;
            //$this->dErrors[] = 'ملف يحتوي على فيروس، تم المسح بنجاح';
        }
            return false;
        //else
        //{
            //$this->dErrors[] = 'ملف يحتوي على فيروس، فشلت عملية المسح';
        //} // end if($delFile)   
    //} // end if($this->scanFile()){
 } // end delFile()



// upload the file
public final function uploadFile($target){

    $this->target = $target;

    if(file_exists($this->target)){
    $moveFile = $this->target.'/'.$this->fileName;
    echo $moveFile.'<br />';

    $upFile = move_uploaded_file($this->fileTmp, $moveFile);

    echo $upFile.'<br />';

    if($upFile) {
        //echo 'تم رفع الملف '.$this->fileName.' بنجاح';
        //$eMsg = 'تم رفع الملف '.$this->fileName.' بنجاح';
        return true;
    }
        //echo 'لم يتم رفع الملف '.$this->fileName.' بنجاح';
        //$eMsg = 'لم يتم رفع الملف '.$this->fileName.' بنجاح';

    }
    else{
        $this->newDir($this->target);
    }
        //$this->eMsg = $eMsg;
} // end uploadFile


// after uploading, for security reason, rename the uploaded file
public final function renameFile($location){

    $this->location = $location;

    // for security reason and better classification, use today date and time
    $todayDate  = date('Y-m-d'); // get today date as a string
    $todayTime  = date('h-i-s'); // get today time as a string
    $now        = time(); // get timestamp

    $this->todayDate    = $todayDate;
    $this->todayTime    = $todayTime;
    $this->now          = $now;

    $renameFrom     = $this->location.'/'.$this->fileName;
    $renameTo       = $this->todayDate.'_'.$todayTime.'_'.$this->now.'.'.$this->fileExt; // i.e: 2013-05-29_08-21-14_1369808474.htm

    $fileDestination = $this->location.'/'.$renameTo;

    $fileNewName            = rename($renameFrom, $fileDestination);

    $this->renameFrom       = $renameFrom;
    $this->renameTo         = $renameTo;
    $this->fileDestination  = $fileDestination;

    // set proper chmod, DO NOT use umask
    chmod($fileDestination, 0644);

} // end renameFile



// filter file
public final function filterFile(){

    // list disable functions, get it from your php.ini
    $disFunctions = array('curl_multi_exec', 'parse_ini_file', 'readfile', 'symlink', 'shell_exec', 'exec', 'proc_close', 'proc_open', 'popen', 'show_source', 'system', 'dl', 'passthru', 'escapeshellarg', 'escapeshellcmd', 'pcntl_alarm', 'pcntl_fork', 'pcntl_waitpid', 'pcntl_wait', 'pcntl_wifexited', 'pcntl_wifstopped', 'pcntl_wifsignaled', 'pcntl_wexitstatus', 'pcntl_wtermsig', 'pcntl_wstopsig', 'pcntl_signal', 'pcntl_signal_dispatch', 'pcntl_get_last_error', 'pcntl_strerror', 'pcntl_sigprocmask', 'pcntl_sigwaitinfo', 'pcntl_sigtimedwait', 'pcntl_exec', 'pcntl_getpriority', 'pcntl_setpriority');

    $this->disFunctions = $disFunctions;

    // get file content

    $cFile = file_get_contents($this->fileDestination, FILE_USE_INCLUDE_PATH);

    foreach($this->disFunctions as $kkeys)
    {
        if(preg_match('#'.$kkeys.'#i', $cFile))
        {
            $this->aErrors[] = 'ملف يحتوي على دوال خطيرة';
            //echo count($this->aErrors).'<br />';

            //echo 'exists<br />';
            //return false;
        }
    } // end foreach
} // end filterFile


####################### Global Functions Start ###############################
// mail function
public final function mailMsg($from, $to, $subject, $message){

// params
 $sensivity = "Sensitivity: Private\n";
 $priority  = "X-Priority: 1 (Higuest)\n";

 $this->from        = $from;
 $this->to          = $to;
 $this->subject     = $subject;
 $this->message     = $message;
 $this->sensivity   = $sensivity;
 $this->priority    = $priority;

 // headers
 $headers = "From:=?UTF-8?B?".base64_encode($this->subject)."?=<'.$this->from.'>\r\n";
 $headers .= $this->sensivity;
 $headers .= $this->priority;

 $this->headers = $headers;


 mail($this->to, $this->subject, $this->message, $this->headers);
} // end mailMsg()
// mail function end


// getIP function
public final function chkip() {
$ip = "";
$proxy = "";
if (isset($_SERVER)) {
    if (isset($_SERVER["HTTP_X_FORWARDED_FOR"])) {
        $ip = $_SERVER["HTTP_X_FORWARDED_FOR"];
        $proxy = $_SERVER["REMOTE_ADDR"];
    } elseif (isset($_SERVER["HTTP_CLIENT_IP"])) {
        $ip = $_SERVER["HTTP_CLIENT_IP"];
    } else {
        $ip = $_SERVER["REMOTE_ADDR"];
    }
} else {
    if ( getenv( 'HTTP_X_FORWARDED_FOR' ) ) {
        $ip = getenv( 'HTTP_X_FORWARDED_FOR');
        $proxy = $_SERVER["REMOTE_ADDR"];
    } elseif ( getenv( 'HTTP_CLIENT_IP' ) ) {
        $ip = getenv( 'HTTP_CLIENT_IP' );
    } else {
        $ip = getenv( 'REMOTE_ADDR' );
    }
}
if (strstr($ip, ',')) {
    $ips = explode(',', $ip);
    $ip = $ips[0];
}
if ($proxy != '') {
    $ip = $ip . '(Proxy: '.$proxy.')';
}
return $ip;
}
################# Global Functions EnD #####################

public final function banIPTables() {

    $this->getIP = $this->chkip();

    $cmd = '/sbin/iptables -A INPUT -s '.$this->getIP.' -j DROP';
    //echo $cmd.'<br />';
    $run = exec($cmd .' 2>&1');
    echo 'run '.$run.'<br />';

} // end banIPTables


public final function banDB($tableName, $fieldName) {

    $this->getIP      = $this->chkip();
    $this->tableName  = $tableName;
    $this->fieldName  = $fieldName;

    /*
    // assuming connection to host and db are already done
    $sql = 'INSERT INTO '.$this->tableName.' VAlUES ('.$this->fieldName.');';
    // you should proceed the query later, depends on you :)
    $this->sql = $sql;

    $query = $connexion->query($sql); 
    */

} // end banIPTables


// get uErrors
public final function getError(){

    //http://www.php.net/manual/en/features.file-upload.errors.php
    switch($this->fileError)
    {
    case 1: // Server side (php.ini)
    case 2: // Form side (MAX_FILE_SIZE)
    $this->uErrors[] = 'الملف كبير الحجم';
    break;

    case 3:
    $this->uErrors[] = 'لم يتم رفع الملف كاملا';
    break;

    case 4:
    $this->uErrors[] = 'المرجو إختيار ملف لرفعه';
    break;

    case 6:
    $this->uErrors[] = 'لا يوجد مجلد مؤقت بالسيرفر';
    break;

    case 7:
    $this->uErrors[] = 'لا يمكن رفع الملف على السيرفر';
    break;

    default:
    $this->uErrors[] = 'خطأ غير معروف';
    break; 
    } // end switch        
} // end getError()

// check if any uErrors
public final function checkErrors(){

    $countuErrors = count($this->uErrors);

    if((IsSet($this->uErrors) && (is_array($this->uErrors) && ($countuErrors > 0))))
    {
        return true;            
    }
        return false;
} // end checkErrors()


// print user errors
public final function printErrors(){

    $countuErrors = count($this->uErrors);

    if((IsSet($this->uErrors) && (is_array($this->uErrors) && ($countuErrors > 0))))
    {
        //echo $this->eMsg;
        echo 'لم يتم رفع الملف '.$this->fileName.' بنجاح';
        echo '<ul>';
        foreach($this->uErrors as $uV)
        {       
            echo '<li>';
            echo $uV;
            echo '</li>';
        }
        echo '</ul>';
    }                
} // end printErrors()


// mail dangerous errors to the admin
public final function mailErrors(){

    $countaErrors = count($this->aErrors);

    if((IsSet($this->aErrors) && (is_array($this->aErrors) && ($countaErrors > 0))))
    {
        // extract errors
        /*
        foreach($this->aErrors as $aV)
        {       
            echo '<li>';
            echo $aV;
            echo '</li>';
        }
        */

        echo 'mail it<br />';
        echo 'transfert to qurantine';
    }                
} // end printErrors()






} // end class

############## USAGE Start ################

$fileField  = 'fileName';
$sendName   = 'Send';

$maxUpSize      = 200000; // max file size: 2KB
$authExt        = array('png', 'gif', 'jpg', 'jpeg', 'docx', 'htm', 'ogv'); // authorized files
$authExtList    = implode(' ،',$authExt);
$current_url    = $_SERVER['REQUEST_URI'];
$target         = 'Images';

if(IsSet($_POST[$sendName]))  {  

// initialize the class
$up = new uploadFiles($fileField);

// check if file uploads is set to ON (1) OR OFF(0) => active or not
if($up->checkUploads()){

//$up->getFileInfo(); // get file information (size, temp name,..)
$up->allowedFileExt($authExt); // list authorized files
$up->allowedFileSize($maxUpSize); // Input max file size

//$up->checkDir('/home/aburayane/www/Images');
$up->newDir('Images');

//echo 'del '.$up->delFile();

//if($up->scanFile()) { // scan file: malware / virus found
    // actions: what to do
    //$up->banIPTables(); // ban throw IPTables
    /*
    $up->banDB('banIPs', 'ip'); // ban into DB


    if($up->delFile()){ // id deleted
    $eMsg = 'ملف يحتوي على فيروس، تم المسح بنجاح';
    } else {
    $eMsg = 'ملف يحتوي على فيروس، فشلت عملية المسح';
    $up->renameFile('Qurantine'); // move the suspecious file to quarantine
    }
    $up->mailMsg('Guard', 'aburayane@gmail.com', 'Virus / Malware Found', $eMsg); // mail admin
    */
//}

if($up->checkErrors() === TRUE)
{
   $up->getError(); // get uErrors 
   $up->printErrors(); // print uErrors 
}
else
{
    $up->uploadFile($target); // upload
    //$up->scanFile();
    $location = 'Images';
    $up->renameFile($location); // rename
    //$up->filterFile(); // filter file

    $up->mailErrors(); // print all uErrors 
    //$up->printErrors(); // get uErrors 

} // end if($up->checkErrors() === TRUE)


} else {
echo 'عملية رفع الملفات غير مفعلة في السيرفر<br />';
} // end if($up->checkUploads()){

} // end if(IsSet($_POST['Send'])) {


################# USAGE EnD #######################
?>

<fieldset style="width: 700px; margin-right: auto; margin-left: auto; border-width: 0px;">

<form name="formUp" method="POST" action="<?php echo $current_url; ?>" enctype="multipart/form-data">
<input type="hidden" name="MAX_FILE_SIZE" value="<?php echo $maxUpSize; ?>" />

<ul>
<li style="list-style: none;">
<label for="file" style="width: 130px; display: inline; float: right; margin-right: 1em; font-weight: bold;">إختر الملف المناسب</label>
<input type="file" name="<?php echo $fileField; ?>" class="fileName" />
</li>

<li style="list-style: none;">
<span style="margin-right: 2em;">
<input type="submit" name="<?php echo $sendName; ?>" class="submitFile" value="باسم الله" />
</span>
<span>حجم الملف لا يتعدى 200 كيلو بايت</span>
<br />
الإمتدادات المقبولة: <span style="color: red; font-weight: bold;"><?php echo $authExtList; ?>.</span>
</li>
</ul>
</form>
</fieldset>
  </body>
</html>

感谢您的平常支持

1 个答案:

答案 0 :(得分:0)

使用finfo函数,您可以检查mime /类型,只允许几个mime /类型,如image / jpeg,text / plain等。要使用这些函数,您需要在phpinfo中使用fileinfo扩展。 请注意,它不会返回$ _FILES或临时文件的准确数据,最好先物理保存文件,如果mime无效则删除文件。见http://php.net/manual/en/function.finfo-file.php

有关mimetypes的列表,请参阅https://gist.github.com/nimasdj/801b0b1a50112ea6a997