PDA

View Full Version : مشکل امنیت در آپلود



PHPOnline
سه شنبه 13 بهمن 1394, 21:25 عصر
سلام

کلاس آپلود :


class EUP {
/**
* in the name of allah
* Easy Upload Prans
* @author Mahdi Sorkhabi
* @version 1.4
* @author website http://prans.info
* @author weblog http://sorkhabi.net
* The followings are the available columns in table 'agents':
* @property string $dir
* @property string $domin
* @property boolean $randomName
* @property integer $minSize
* @property integer $maxSize
* @property array $format
* @property array $log
* @property array $result
*/
private $_attributes = array(
'dir',
'domin',
'randomName',
'minSize',
'maxSize',
'format',
'log' => array (),
'result' => array(),
);
public function __construct ($dir,$domin,$format = array ('pdf'=> 'application/pdf'),$randomName = false,$minSize = 1024,$maxSize = 1048576)
{
$this->_attributes ['domin'] = $domin;
$this->_attributes ['dir'] = $dir;
$this->_attributes ['format'] = $format;
$this->_attributes ['randomName'] = $randomName;
$this->_attributes ['minSize'] = $minSize;
$this->_attributes ['maxSize'] = $maxSize;
}
/**
* Magic Getter method
* @param string $fileName The name of attribute
*
* @return mixed The value of attribute
*/
public function __GET($fileName)
{
if(isset($this->_attributes)) {
return $this->_attributes[$fileName];
}
}
/**
* Magic setter method
* @param string $fileName The name of attribute
* @param mixed $value The value of attribute
*/
public function __SET($fileName, $value)
{
if(isset($this->_attributes)) {
$this->_attributes[$fileName] = $value;
}
}
/**
* Check the size
* @param integer $size The size to check
*
* @return boolean Whether the size is valid
*/
private function checkMaxSize($size)
{
return ($size <= $this->maxSize);
}
/**
* Check the size
* @param integer $size The size to check
*
* @return boolean Whether the size is valid
*/
private function checkMinSize($size)
{
return ($size >= $this->minSize);
}
/**
* Get the file extension
* @param string $fileName The filename
* @param boolean $lower Whether to return the extension in lowercase
*
* @return string The file extension
*/
private function getExtension($fileName)
{
mb_internal_encoding('utf-8');
return mb_substr($fileName, mb_strrpos($fileName, '.') + 1);
}
private function checkFormat($fileName,$fileType)
{
$extension = $this->getExtension ($fileName);
foreach ($this->_attributes ['format'] as $format => $MIME){
if ($extension === $format and $fileType === $MIME){
return true;
}
}
return false;
}
/**
* Get the safe filename based on the original name
* @param string $fileName The original filename
*
* @return string The new filename
*/
private function newFileName($fileName)
{
$extension = '.' . $this->getExtension($fileName);
if ($this->_attributes ['randomName']){
return md5(rand(100000, 999999) . $fileName . rand(100000, 999999)) . $extension;
}else{
return str_replace('.', '-', basename($fileName,'.' . $this->getExtension ($fileName))) . $extension;
}
}
/**
* Create a unique name
* @param string $fileName The original filename
*
* @return string The new filename
*/
private function uniqueName($fileName)
{
$baseName = basename($fileName,'.' . $this->getExtension ($fileName));
$extension = '.' . $this->getExtension($fileName);
$counter = 2;
while(file_exists($this->dir . $fileName)) {
$fileName = $baseName . '-' . $counter . $extension;
$counter++;
}
return $fileName;
}
/**
* Add log
* @param string $log The log to add
*/
private function addLog($log)
{
$this->_attributes ['log'] = $log;
}
/**
* Do the real upload process
* @param array $element The file element (an element of $_FILES array)
*
* @return boolean|false The uploaded file URL on success, false otherwise
*/
private function uploadFile ($element,$key = false){
$this->_attributes ['log'] = '';
if ($key === false){
list($name, $tempName, $error, $size, $mimeType) = array($element['name'], $element['tmp_name'], $element['error'], $element['size'], $element['type']);
}else{
list($name, $tempName, $error, $size, $mimeType) = array($element['name'][$key], $element['tmp_name'][$key], $element['error'][$key], $element['size'][$key], $element['type'][$key]);
}
if (trim ($name) !== '') {
if ($error == 0) {
if($this->checkFormat ($name,$mimeType)) {
if($this->checkMinSize($size)) {
if($this->checkMaxSize($size)) {
$newName = $this->newFileName($name);
$newName = $this->uniqueName($newName);
if(move_uploaded_file($tempName, $this->dir . $newName)) {
$this->addLog ('فایل "' . $name . '" با موفقیت آپلود شد');
$file = $this->domin . $newName;
}
else {
$this->addLog('مشکلی در اجرای عملیات رخ داد (آپلود فایل "' . $name . '")');
}
}
else {
$this->addLog('سایز فایل "' . $name . '" بیش از اندازه مجاز می باشد');
}
}
else{
$this->addLog('سایز فایل "' . $name . '" کم تر از حجم مجاز می باشد');
}
}
else {
$this->addLog('پسوند فایل "' . $name . '" مجاز نیست');
}
}
else{
$this->addLog('مشکلی در اجرای عملیات رخ داد (آپلود فایل "' . $name . '")');
}
if(isset ($file)){
return array (
'result' => true,
'url' => $file,
'log' => $this->_attributes ['log'],
'fileName' => $name,
);
}else{
return array (
'result' => false,
'url' => '',
'log' => $this->_attributes ['log'],
'fileName' => $name,
);
}
}
return false;
}
/**
* Execute the upload process
* @param array $element (an element of $_FILES array)
*
* @return array|string The upload result in single mode or an array of results in multiple mode
*/
public function upload($element,$multiple = false) {
if (!is_dir ($this->_attributes ['dir'])){
mkdir ($this->_attributes ['dir']);
}
if($multiple) {
if(isset ($element ['name'])){
$count = count ($element ['name']);
for ($key = 0;$key < $count; $key++) {
$result = $this->uploadFile($element,$key);
if ($result){
$this->_attributes ['result'][$key] = $result;
}
}
return $this->_attributes ['result'];
}
}else{
$result = $this->uploadFile($element,false);
if ($result){
$this->_attributes ['result'][0] = $result;
}
return $this->_attributes ['result'];
}
}
public function checkUpload ($uploadResult){
return (isset ($uploadResult ['0']) ? true : false);
}
}
?>


پیش رفتم و فایل ها رو به راحتی آپلود کردم ، اما از لحاظ امنیتی مشکلاتی داره ، مثل آپلود شل به راحتی انجام میشه !
به چه شکل باید این حفره رو پوشش بدم ؟ تا فقط فایل های مد نظرم آپلود بشن

ممنون از شما

PHPOnline
سه شنبه 13 بهمن 1394, 21:45 عصر
مثال :


<?php
if(isset ($_POST ['multi_ok'])){
$eup = new EUP ('test/','http://site.com/test/');
$result = $eup->upload ($_FILES ['multi'],true);
// نمایش فایل های آپلود شده
if ($eup->checkUpload ($result)){
foreach ($result as $re){
if ($re['result']){
echo $re ['log'] . '<br />آدرس فایل : <br />'.$re ['url'] . '<br />';
}else{
echo $re ['log'] . '<br />';
}
}
}
}
?>
<meta charset="UTF-8">
<body dir="rtl">
<form method="post" enctype="multipart/form-data">
<table>
<tr><td>فایل :</td><td><input type="file" name="multi[]"></td></tr></tr>
<tr><td>فایل :</td><td><input type="file" name="multi[]"></td></tr></tr>
<tr><td>فایل :</td><td><input type="file" name="multi[]"></td></tr></tr>
<tr><td>فایل :</td><td><input type="file" name="multi[]"></td></tr></tr>
<tr><td></td><td><input type="submit" name="multi_ok" value="آپلود بفرما !!!"></td></tr></tr>
</table>
</form>
</body>

Unique
چهارشنبه 14 بهمن 1394, 03:34 صبح
دوست عزیز ، موارد امنیتی در مورد Upload یکی دو تا نیست که اون هم بخواهیم توی کد شما رفعش کنیم ،‌ اما از جمله موارد مهم :

۱ - فایل ها را توی پوشه ای قرار بدیم که دسترسی خیلی محدود و فقط از طرف برنامه داره و امکان تفسیر فایل های PHP براش وجود نداره
۲ - فایل ها را بدون پسوند ذخیره کنیم ،‌ نام فایل را توی پایگاه داده برای ارجاعات بعدی قرار بدیم.
۳ - اگه دیگه خیلی نگران هستی یک نرم افزار Antivirus یا Anti Malware نصب کن و فایل ها را پس از ارسال بده چک کنه بعد ذخیره کن.

بررسی پسوند و GD و سرآیند های ابتدای فایل روش های ۱۰۰٪ نیستند.

leaping
چهارشنبه 14 بهمن 1394, 09:59 صبح
این روشها به نظرم خیالت رو تا حد زیادی راحت میکنه
1- یک پوشه برای فایلهات درست کن و کلیه دسترسی های خارجی به اون پوشه رو اعم از Write و Read و Execute رو براش ببند
2- هنگام آپلود اسامی فایلهارو توی دیتابیس ذخیره کن
3- فایلهارو بدون پسوند ذخیره کن
4- هنگام بازخوانی فایلها توسط کاربر این عمل رو توسط PHP و در قالب Header انجام بده به این ترتیب فقط اجازه روندهای مورد نظرت رو صادر کن

PHPOnline
چهارشنبه 14 بهمن 1394, 18:25 عصر
ممنون از پاسخ دو بزرگوار
پس با این وجود ، این کد آپلود رو میشه استفاده کرد ، و باید پوشه آپلود فایل ها رو کنترل کرد تا فایلی قابلیت اجرا نداشته باشه

PHPOnline
چهارشنبه 14 بهمن 1394, 18:39 عصر
RemoveHandler .php .phtml .php3
RemoveType .php .phtml .php30

از این کد برای غیرفعال کردن فایل های پی اچ پی استفاده کنم در فولدر آپلود ، مفید خواهد بود ؟

plague
پنج شنبه 15 بهمن 1394, 23:53 عصر
RemoveHandler .php .phtml .php3
RemoveType .php .phtml .php30

از این کد برای غیرفعال کردن فایل های پی اچ پی استفاده کنم در فولدر آپلود ، مفید خواهد بود ؟
اگه از این روش هم بخای استفاده کنید خیلی چیزا رو از این لیست جا انداختی
php از یک تا شش میتونی بندازی تهش ! از اون که بگزریم کلی شل با پایتان و پرل و ... هست که تو لیست شما نیست باید یه فکری برای اونا بکنید

Unique
جمعه 16 بهمن 1394, 02:49 صبح
بهتره کلا دسترسی فولدر را بگیری ! Permission را بگذار روی 700. کلا بای دبی خیال دسترسی مستقیم به اصل فایل های آپلود شده بشی.

PHPOnline
جمعه 16 بهمن 1394, 16:02 عصر
بهتره کلا دسترسی فولدر را بگیری ! Permission را بگذار روی 700. کلا بای دبی خیال دسترسی مستقیم به اصل فایل های آپلود شده بشی.

چون باید کاربران عادی فایل های آپلود شده رو بتونن دانلود کنند ، مشکل You do not have permission to access this document. پیش میاد موقع دانلود

PHPOnline
جمعه 16 بهمن 1394, 16:03 عصر
اگه از این روش هم بخای استفاده کنید خیلی چیزا رو از این لیست جا انداختی
php از یک تا شش میتونی بندازی تهش ! از اون که بگزریم کلی شل با پایتان و پرل و ... هست که تو لیست شما نیست باید یه فکری برای اونا بکنید

یعنی با تهیه یک لیست کامل از این موارد میتونیم مطمئن بشیم ک شل کار نخواهد کرد ؟

PHPOnline
جمعه 16 بهمن 1394, 16:07 عصر
دوست عزیز ، موارد امنیتی در مورد Upload یکی دو تا نیست که اون هم بخواهیم توی کد شما رفعش کنیم ،‌ اما از جمله موارد مهم :

۱ - فایل ها را توی پوشه ای قرار بدیم که دسترسی خیلی محدود و فقط از طرف برنامه داره و امکان تفسیر فایل های PHP براش وجود نداره
۲ - فایل ها را بدون پسوند ذخیره کنیم ،‌ نام فایل را توی پایگاه داده برای ارجاعات بعدی قرار بدیم.
۳ - اگه دیگه خیلی نگران هستی یک نرم افزار Antivirus یا Anti Malware نصب کن و فایل ها را پس از ارسال بده چک کنه بعد ذخیره کن.

بررسی پسوند و GD و سرآیند های ابتدای فایل روش های ۱۰۰٪ نیستند.

اگ فایل ها رو بدون پسوند ذخیره کنیم و آدرس و پسوند فایل ها را در پایگاه داده ثبت کنیم ، در زمان دانلود فایل به مشکل میخوریم ، چرا که فایل ها بدون پسوند هستند
اگر کاربر بخواد دانلود کنه با فایل بدون پسوند روبرو میشه ک کاربردی براش نداره ! اگر هم پسوند رو بخواهیم از دیتابیس بگیریم و به فایل بچسبونیم ، همچین چیزی امکان پذیره ؟ :متفکر:

plague
جمعه 16 بهمن 1394, 17:09 عصر
یعنی با تهیه یک لیست کامل از این موارد میتونیم مطمئن بشیم ک شل کار نخواهد کرد ؟

به نظر من نه ... میتونه مفید باشه و استفاده کن شما ولی به تنهایی حتی میتونه آسیپ پزیر هم باشه چون باعث میشه که شما با خیال راحت بری دنبال کارت و بقیه جاها رو شل بگیری به امید این فایل ولی htaccess هم یه فایله که هکر میتونه با نفوذ به سرور تغییر بده یه کار با مزه ای که هکر ها میکنن اینه که میان از این لیست 1 فرمت رو حذف میکنن و شل ها رو با همون فرمت آپلود میکنن شما هم هر روز برو اچ تی اکسسز رو نگاه کن عمرا متوجه نمیشی که چیزی حذف شده !

مطمئن ترین راه ها اینا

1 - اگه آپلودی ها عکس هستن از روی عکس یه کپی بساز و زخیره کن و عکس آپلود شده کاربر رو حذف کن
2 - اگه فایل هستن
دسترسی مستقیم به کاربر ها نده
فایل ها رو تو یه دایرکتوری بریز که کاربر ها دسترسی مستقیم بهش نداشته باشن
اسم فایل ها رو بریز تو دیتابیس و مثلا با استفاده از id که دیتابیس میده فایل ها رو به کاربر ها ارائه کن و هرکی خواست دانلود کنه با کد php فایل ها رو بخون و براشون ارسال کن (دیگه اینجا رو باید خلاقیت به خرج بدین )
یا اینکه
یه سرور حجمی بگیر برای فایل ها با ftp بریز اونجا فایل های آپلودی رو

موارد مشخص دیگه مثل تغییر نام فایل ها روی سرور و چک کردن فرمت ومیم تایپ هم که بدیهی هستن باید انجام بشن

PHPOnline
جمعه 16 بهمن 1394, 17:32 عصر
به نظر من نه ... میتونه مفید باشه و استفاده کن شما ولی به تنهایی حتی میتونه آسیپ پزیر هم باشه چون باعث میشه که شما با خیال راحت بری دنبال کارت و بقیه جاها رو شل بگیری به امید این فایل ولی htaccess هم یه فایله که هکر میتونه با نفوذ به سرور تغییر بده یه کار با مزه ای که هکر ها میکنن اینه که میان از این لیست 1 فرمت رو حذف میکنن و شل ها رو با همون فرمت آپلود میکنن شما هم هر روز برو اچ تی اکسسز رو نگاه کن عمرا متوجه نمیشی که چیزی حذف شده !

مطمئن ترین راه ها اینا

1 - اگه آپلودی ها عکس هستن از روی عکس یه کپی بساز و زخیره کن و عکس آپلود شده کاربر رو حذف کن
2 - اگه فایل هستن
دسترسی مستقیم به کاربر ها نده
فایل ها رو تو یه دایرکتوری بریز که کاربر ها دسترسی مستقیم بهش نداشته باشن
اسم فایل ها رو بریز تو دیتابیس و مثلا با استفاده از id که دیتابیس میده فایل ها رو به کاربر ها ارائه کن و هرکی خواست دانلود کنه با کد php فایل ها رو بخون و براشون ارسال کن (دیگه اینجا رو باید خلاقیت به خرج بدین )
یا اینکه
یه سرور حجمی بگیر برای فایل ها با ftp بریز اونجا فایل های آپلودی رو

موارد مشخص دیگه مثل تغییر نام فایل ها روی سرور و چک کردن فرمت ومیم تایپ هم که بدیهی هستن باید انجام بشن

ممنون ک وقت میزارید و راهنمایی مکینید دوست عزیز
فایل های آپلودی هم عکس هست هم فایل
بعد از آپلود باید این فایل ها در اختیار کاربران قرار بگیره و بتونن دانلود کنن به همین دلیل نمیتونم دسترسی به فولدر رو ندم

فکر کنم مطمئن ترین روش :
یه سرور حجمی بگیر برای فایل ها با ftp بریز اونجا فایل های آپلودی رو
همین باشه ، درسته ؟

plague
شنبه 17 بهمن 1394, 00:31 صبح
اینکه دسترسی مستقیم ندی به کاربر به این معنی نیست که کاربر ها نتونن به فایل دسترسی پیدا کنن
مطمئنا وقتی شما فایل رو سرور میریز برای کسی هستن این فایل ها دکور که نیستن
گفتم که شما با php فایل ها رو اصطلاحا سرو میکنی و به کاربر میدی یعنی ه کد php مینویسی که کاربر آیدی اون فایل رو که میخاد دانلود کنه میبره به اون کد میده
کد میره از دایرکتوری میخونه و میده به کاربر
یه سرچ بکن php force download نمونه کد زیاد هست تو نت

البته برای عکس ها اگه قراره تو سایت نمایش داده بشن نیاز نیست به نظر من و همون روشی که گفتم جواب میده


من نمیدونم فایل هات چی هستن و سطح دسترسی بهشون چجوریه (پولی هستن یا قراره همه دسترسی پیدا کنن - عمومی هستن یا خصوصی ) ولی در کل سرور حجمی روش خوبیه حداقل خیالت راحته که فایل ها روی هاستی که کدت قرار داره نیستن