رمزنگاری فایل ها در PHP - فاکتور مهم برای افزایش امنیت سمت سرور
#1
Lightbulb 
به نام خدا؛
سلام دوستان امیدوارم حالتون خوب باشه...
حتماً تا حالا براتون پیش اومده که بخواین یک فایلی که داخل سرور یا هاستتون وجود داره رو رمزنگاری کنین تا محتوای فایل غیر قابل مشاهده باشه.
امروز قصد داریم راجع به رمزنگاری فایلهای آپلود شده توی سرور یا هاستمون صرف نظر از فرمتشون صحبت کنیم. برای رمزنگاری رشته ها در PHP توابع زیادی به صورت پیشفرض در PHP تعریف شده اما برای رمزنگاری فایلها در PHP تابعی که به صورت پیشفرض در این زبان تعریف شده باشه متأسفانه موجود نیست. در ورژن های قبل از 7.2 این زبان با استفاده از افزونه (extension) mcrypt این امکان وجود داشت که با استفاده از این افزونه فایلها رو رمزنگاری کرد. اما متأسفانه این امکان در ورژن هفتم PHP وجود نداره. پس باید به دنبال راه جایگزین بود. امروز قصد داریم که فایلها رو با استفاده از الگوریتم AES-128-CBC رمزنگاری و رمزگشایی کنیم.
اجازه بدین اول با تابع رمزنگاری فایل شروع کنیم.
رمزنگاری فایل:
کد php:
<?php

/**
 * @author Master Badfar
 * @copyright 2020
 */ 
// تابع رمزنگاری به کمک الگوریتم AES-128-CBC
define('FILE_ENCRYPTION_BLOCKS'10000);

function 
encryptFile($source$key$dest)
{
    
$key substr(sha1($keytrue), 016);
    
$iv openssl_random_pseudo_bytes(16);

    
$error false;
    if (
$fpOut fopen($dest'w')) {
        
fwrite($fpOut$iv);
        if (
$fpIn fopen($source'rb')) {
            while (!
feof($fpIn)) {
                
$plaintext fread($fpIn16 FILE_ENCRYPTION_BLOCKS);
                
$ciphertext openssl_encrypt($plaintext'AES-128-CBC'$keyOPENSSL_RAW_DATA$iv);
                
$iv substr($ciphertext016);
                
fwrite($fpOut$ciphertext);
            }
            
fclose($fpIn);
        } else {
            
$error true;
        }
        
fclose($fpOut);
    } else {
        
$error true;
    }

    return 
$error false $dest;
}
// پایان تابع
//
// دریافت نام فایل موردنظر برای رمزنگاری و ذخیره آن در یک متغیر
$fileName $_GET['file'];
// تعریف کلید خصوصی جهت رمزگشایی
$key 'X@7O^5zFv7y2svB';
// استفاده از تابع تعریف شده برای رمزنگاری
encryptFile($fileName$key$fileName '.enc');
// حذف فایل اصلی
unlink($fileName);
// نمایش پیغام موفقیت آمیز بودن
echo "Done!";
?>
برای اینکه بتونین یک فایلی که در دایرکتوری که این فایل PHP قرار داره رو رمزنگاری کنین باید ریکوئستی مشابه نمونه زیر ارسال کنین:
کد:
http://yourhost.com/file.php?file=x
شما باید به جای عبارت x برای پارامتر file نام فایل موردنظرتون رو به همراه فرمتش درج کنین. 
همونطور که در کد بالا می بینید یک کلید خصوصی هم تعریف کردیم که برای رمزگشایی فایل به کارمون میاد. هر چی این کلید خصوصی طولانی تر باشه و کاراکترهای مختلفی داخلش استفاده شده باشه بهتره چرا که باعث میشه کرکر (Cracker) یا هکر نتونه با حملاتی مثل وردلیست یا بروت فورس نتیجه شاخصی بگیره. 
بعد از اجرای کد بالا فایل موردنظر شما با فرمت .enc همونطور که در کد تعریف کردیم (میتونین این فرمت رو به دلخواه خودتون تغییر بدین) ذخیره میشه. یعنی اگر برای مثال نام فایل شما image.jpg باشه فایل رمزنگاری شده ای که این کد به شما تحویل میده image.jpg.enc خواهد بود. در ضمن فایل اصلی که رمزنگاری کردین بعد از انجام پروسه رمزنگاری حذف میشه چرا که هدف ما این هست که محتوای فایل قابل مشاهده نباشه. 
رمزگشایی فایل:
 برای رمزگشایی فایل رمزنگاری شده ای که در دایرکتوری این فایل PHP قرار داره از این کد استفاده میکنیم:
کد php:
<?php

/**
 * @author Master Badfar
 * @copyright 2020
 */ 
// تابع رمزگشایی الگوریتم AES-128-CBC
function decryptFile($source$key$dest)
{
    
$key substr(sha1($keytrue), 016);

    
$error false;
    if (
$fpOut fopen($dest'w')) {
        if (
$fpIn fopen($source'rb')) {
            
$iv fread($fpIn16);
            while (!
feof($fpIn)) {
                
$ciphertext fread($fpIn16 * (FILE_ENCRYPTION_BLOCKS 1)); 
                
$plaintext openssl_decrypt($ciphertext'AES-128-CBC'$keyOPENSSL_RAW_DATA$iv);
                
$iv substr($ciphertext016);
                
fwrite($fpOut$plaintext);
            }
            
fclose($fpIn);
        } else {
            
$error true;
        }
        
fclose($fpOut);
    } else {
        
$error true;
    }

    return 
$error false $dest;
}
// پایان تابع
//
// دریافت نام فایل موردنظر برای رمزنگاری و ذخیره آن در یک متغیر
$fileName $_GET['file'];
// تعریف کلید خصوصی جهت رمزگشایی
$key 'X@7O^5zFv7y2svB';
// استفاده از تابع تعریف شده برای رمزگشایی
decryptFile($fileName '.enc'$key$fileName '.dec');
// نمایش پیغام موفقیت آمیز بودن
echo "Done!";
?>
برای رمزگشایی فایل موردنظرتون باید ریکوئستی مشابه نمونه زیر ارسال کنین:
کد:
http://yourhost.com/file.php?file=y
به جای عبارت y برای پارامتر file شما باید نام فایل رمزنگاری شده خودتون رو با احتساب فرمت و پسوند رمزنگاری که انتخاب کردین (توی بخش رمزنگاری صحبت کردم راجع بهش؛ من برای مثال اینجا .enc رو انتخاب کردم) وارد کنین تا فایل موردنظر رمزگشایی بشه.
فایل رمزگشایی شده با پسوند .dec ذخیره میشه که شما میتونین دقیقاً مثل پسوند رمزنگاری این پسوند رو هم به سلیقه خودتون شخصی سازی کنین. یعنی اگر شما فایل رمزنگاری شده image.jpg.enc رو با استفاده از این کد رمزگشایی کردین فایل رمزگشایی شده نامش میشه image.jpg.dec. پس شما میتونین روی فایل رمزگشایی شده پردازش داشته باشین.
در ضمن کلید خصوصی که در بخش رمزنگاری تعیین کردین رو باید حتماً برای رمزگشایی به خاطر داشته باشین.
نکته کاربردی برای بهینه سازی حجم کدها:
کدهایی که بنده قرار دادم تقریباً طولانی هستند. برای اینکه کدها رو کوتاه تر کنیم میتونیم از تکنیک include یا require در زبان PHP استفاده کنیم. 
در واقع به نوعی ما فانکشن (تابع) رمزنگاری یا رمزگشایی رو به تنهایی در یک فایل مجزا مثلاً با نام function.php قرار میدیم و بعد اون رو توی یک فایل دیگه فراخوانی میکنیم. 
دقت کنین که برای فراخوانی یک فایل PHP دیگه در فایل PHP دیگه راه های زیادی هست که بسته به شرایط به کار میاد. ولی به طورکلی همونطور که گفتم دو تابع require و include باید استفاده بشن. البته بماند که require_once و include_once رو هم داریم که یعنی یک بار فایل به روش require یا include فقط در همون قسمتی از برنامه که تعیین کردیم و نه کل برنامه مون فراخوانی بشه. اما تفاوت include با require در چی هست؟
وقتی ما از include استفاده میکنیم اگر اون فایل PHP که مشخص می کنیم که فراخوانی بشه مشکلی داشته باشه ادامه برنامه ما اجرا میشه ولی اگر از require استفاده کنیم و مشکلی در فایل PHP فراخوانی شده باشه ادامه برنامه اجرا نمیشه و برنامه از قسمت فراخوانی فایل متوقف میشه و به پایان میرسه.
با این توضیحات میفهمیم که در حالتی که الان باهاش مواجه هستیم باید فایل function.php رو از طریق تابع require فراخوانی کنیم. 
دستور فراخوانی با تابع require یا include در کد PHP ما به این شکل میشه:
کد php:
include/require ('file.php'); 
اسم دیگه این تکنیک اصطلاحاً ساختن مستر پیج و صفحات فرعی هست. همونطور که گفته شد استفاده از این تکنیک میتونه کدهای شما رو کوتاه تر بکنه و البته اگر مشکلی هم پیش بیاد پیدا کردن مشکل خیلی ساده تر خواهد بود.
پ.ن: دقت کنین که همونطور که در ابتدای تاپیک گفتم شما میتونین هر فایلی توی هاستتون رو با هر فرمتی رمزنگاری و رمزگشایی کنین. میخواد فایل شما یک تصویر باشه یا یک فایل txt یا فایل json و یا هر فایلی. در ضمن چیزی که باعث میشه امنیت این روش بیشتر بشه استفاده از کلید خصوصی ایمن و دارای طول مناسب و تصادفی هست. چرا که تصادفی بودن باعث میشه مهاجم نتونه با روش های حمله جامع آماری و یا لیست های از پیش آماده شده کار زیادی پیش ببره. پس حتماً به این موضوع دقت داشته باشین.
استفاده از این روش و اعمال یکسری تنظیمات در فایل .htaccess میتونه امنیت سمت سرور شما رو تا حد بسیار بالایی تأمین کنه و دیگه نگرانی بابت مقوله امنیت نداشته باشین. البته بماند که امنیت هیچ وقت صد درصد نیست!
 امیدوارم که از این مطلب کاربردی لذت برده باشین.
خوشحال میشم نظراتتون رو بیان کنین.
با آرزوی بهترین ها...
غایب
  پاسخ


 سپاس شده توسط: S.L.F ، oak ، M.gh ، hasansanaei ، _mohammad_javad_ ، amin hosseini
#2
داداش دمت گرم خیـــــلی مهم بود این موضوع
یکم استراحت کن خسته میشی از بس آموزش گذاشتی  39
یک سوال تو انگشتای درد نمی گیرن از بس تایپ می کنی؟
  پاسخ


 سپاس شده توسط: Master Badfar ، oak
#3
(1399/1/11، 07:22 عصر)""M.gh نوشته است: داداش دمت گرم خیـــــلی مهم بود این موضوع
یکم استراحت کن خسته میشی از بس آموزش گذاشتی  39
یک سوال تو انگشتای درد نمی گیرن از بس تایپ می کنی؟



نه راستش من مشکلی با تایپ کردن ندارم. یک دینی هست که باید ادا بشه.
احتمالاً یک مدتی غایب بشم برای همین دارم سعی میکنم مباحث کاربردی که توی آموزشها کمتر بهش پرداخته شده رو بهشون بپردازم و بعد از اینکه دوران غیبت صغری تموم شد یک دوره آموزشی PHP یا زبانهای رایج سمت سرور مثل node.js برگزار کنم که برای اعضا مفید واقع بشه. 
البته ممکنه این غیبت حدود 20 ماهی طول بکشه و مسلماً تا اون موقع انجمن تغییرات زیادی میکنه و حتماً چنین دوره هایی توسط دوستان دیگه برگزار میشه.
غایب
  پاسخ


 سپاس شده توسط:
#4
یا خدا
20 ماه
چه خبره
بدبخت شدیم رفت  20 
پس تا میتونی آموزش بده بیرون.
  پاسخ


 سپاس شده توسط:
#5
(1399/1/11، 07:47 عصر)""M.gh نوشته است: یا خدا
20 ماه
چه خبره
بدبخت شدیم رفت  20 
پس تا میتونی آموزش بده بیرون.
سعی خودم رو میکنم که آموزش های مختلفی رو منتشر کنم. 
شما عزیزان هم اگر مواردی که براتون کاربردی واقع میشه رو بیان کنین تا من بهشون بپردازم مطالب پربارتر میشه.
در طی اون بیست ماه بدون شک اتفاقات خوبی توسط بقیه دوستان رقم میخوره.
غایب
  پاسخ


 سپاس شده توسط: M.gh
#6
میشه یه تاپیک بزنی که توش یه کد بزاری که مثلا ما وقتی این :
کد:
myhost.ir/file.php?file=test.txt
آدرس رو ریکوئست می کنیم محتویات فایل txt ای که در ریکوئست نوشتیم رو echo کنه.
 
  پاسخ


 سپاس شده توسط:
#7
(1399/1/11، 08:55 عصر)""M.gh نوشته است: میشه یه تاپیک بزنی که توش یه کد بزاری که مثلا ما وقتی این :
آموزش بعدی کار با توابع فایل خواهد بود. البته اگر به کدهای این آموزشی که تهیه کردم قسمت باز کردن و یا ریختن اطلاعات در فایل دقت کنی حدوداً یک سری چیزا رو متوجه میشی. ولی بازم مطالب ریزی هست که لازمه بیان بشه. انشاالله راجع بهش مینویسم.
 
غایب
  پاسخ


 سپاس شده توسط:
#8
22
بازم ممنون  4
با همون تاپیک کار با جیسون  در پی اچ پی فهمیدم
پس یه تاپیک بزن که
که مثلا ما یک فایل txt در هاست داریم بعد وقتی همچین آدرسی رو پست می کنیم ،
کد:
myhost.ir/file.php?text=example
اون متنی که تو پست نوشتیم رو ( example) رو در فایل متنی ای که داخل فایل php آدرسش رو نوشتیم بنویسه 
یعنی مثلا  فایل txt من محتویاتش این شکلیه:
 
کد:
hello
 حالا وقتی پست کردیم مثلا بجای  example نوشتیم goodby فایل txt این شکلی بشه :
 
کد:
hello
goodby
 
  پاسخ


 سپاس شده توسط:
#9
(1399/1/11، 09:21 عصر)""M.gh نوشته است: 22
بازم ممنون  4
با همون تاپیک کار با جیسون  در پی اچ پی فهمیدم
پس یه تاپیک بزن که
که مثلا ما یک فایل txt در هاست داریم بعد وقتی همچین آدرسی رو پست می کنیم ،


بزار همینجا جوابت رو بدم گرچه که میدونم جاش نیست!
طبق توضیحاتت چون فایل تکستی که میخوای قبلاً وجود داره پس لازم نیست ایجاد بشه. بنابراین کد به این شکل میشه:
کد php:
<?php

/**
 * @author Master Badfar
 * @copyright 2020
 */
   // قطع نمایش خطاهای مفسر PHP
ini_set('display_errors'0);
error_reporting(~E_WARNING & ~E_NOTICE & ~E_STRICT);

// دریافت نام فایل و ذخیره نام فایل در متغیر
$filename $_GET['filename'];
// دریافت مقدار موردنظر جهت اضافه شدن به فایل و ذخیره آن در یک متغیر
$data $_GET['data'];
// متغیر میزان ارور
$error 0;
// بررسی موجود بودن فایل وارده توسط کاربر
if (!file_exists($filename)){
    echo 
"The entered file is not avialable!";
    
$error++;
    
// بررسی خالی نبودن پارامتر data
    
}elseif(empty($data)){
        echo 
"You should enter something as data!";
        
$error++;
}
// ریختن اطلاعات موردنظر کاربر در فایل
if ($error == 0){
$fp fopen($filename"a") or die("Unable to open ' " $filename " '");
fwrite($fp$data);
fwrite($fp"\n");
// نمایش موفقیت آمیز بودن
echo "Done!";
// بستن فایل
fclose($fp);
}
?>
برای استفاده از کد کافیه چنین ریکوئستی بزنی:
کد:
http://yourhost.com/file.php?filename=x.txt&data=y
پارامتر filename نام فایلت هست که باید با احتساب فرمتش نامش رو وارد کنی. پارامتر data هم هر مقداری بهش بدی به فایلت اضافه میکنه و برای ریکوئست های آینده هم متنی رو که قصد داری به فایل اضافه کنی توی خطوط بعد ذخیره میکنه و نه جلوی متون قبلی. 
دقت کن که باید آرگومان دوم تابع fopen() رو a قرار بدی تا محتویات قبلی فایل حذف نشه و در ادامه محتویات قبلی بتونی محتویات جدید رو ثبت کنی. اگر آرگومان دوم رو w قرار بدی محتویات قبلی با هر بار ریکوئست پاک میشن و فقط اطلاعات جدید ثبت شده به فایل اضافه میشن.
موفق باشی 16
غایب
  پاسخ


 سپاس شده توسط: M.gh
#10
آقا خیلی خیلی خیلی ممنونم.  1

حیف نمی تونم بهت اعتبار بدم !
  پاسخ


 سپاس شده توسط: Master Badfar


موضوع‌های مشابه…
موضوع نویسنده پاسخ بازدید آخرین ارسال
  آموزش پروژه محور ساخت بازی مار و پله mohsen_nasri 6 3,676 1403/10/24، 09:38 عصر
آخرین ارسال: Tggi
Star مهم آموزش خروجی اندروید روی سیستم شخصی rezamms 128 85,312 1403/10/23، 04:58 عصر
آخرین ارسال: Tggi
  مهم آموزش تصویری خروجی مستقیم - یکبار برای همیشه! rezamms 33 20,552 1401/2/13، 09:39 عصر
آخرین ارسال: kamran_cn
  خروجی اندرید davinmstr1 2 2,551 1400/8/4، 10:23 عصر
آخرین ارسال: ᔕinaᗪehghani
  AAB (بسته برنامه اندروید) چيست؟ + نحوه خروجي گرفتن در كرودوا ᔕinaᗪehghani 15 8,420 1400/6/21، 01:55 صبح
آخرین ارسال: mehdi1100

پرش به انجمن: