درس دوازدهم- موارد بیشتری از امنیت تارنما
مقدمه
در درس پیشین مواردی از رعایت امنیت در ساخت تارنما را معرفی کردیم. در این درس به چند مورد مهم دیگر می پردازیم.
ارزیابی فایلها با توجه به نوع آنها
در درس ارسال فایل (عکس) یاد گرفتیم که چطور یک فایل را به سیستم ارسال کرده و از آن استفاده کنیم. نکته ای که در این بحث مورد توجه است٬ این است که این ارسال امکان نفوذ به سیستم را از طریق فایل فراهم میکند. البته برای ارسال فایل ما از فیلتری برای بررسی نوع فایل استفاده کردیم که آن به شکل گرفتن نوع فایل از متغیر: $_FILES['upload']['type'] نمایان شد.
این نوع بررسی نوع فایل توسط مرورگر فراهم میشود که به نوعMIME فایل رجوع میکند. علی رغم اینکه این بررسی کار مناسبی است٬ اما هنوز راه های نفوذ وجود دارند٬ بر همین اساس به راههای دیگر که پیاچپی فراهم کرده اشاره میکنیم.
شیوهای که در پیاچپی نسخه ۵.۳ به بعد اضافه شده است به این شکل است: یک ظرفی برای شناسایی نوع فایل وجود دارد که نوع فایل و کدگذاری آن را بر اساس جستجوی اعداد جادویی در داخل محتوای فایل نمایان میکند. به این معنی که اطلاعاتی که فایلی را تشکیل میدهند٬ بر اساس نوع فایل با اعداد یا کاراکترهای ویژه آن فایل آغاز میشوند. بطور مثال فایلهایGIF (نوعی فایل برای عکس)٬ باید با کاراکتر و کد اسکی (ASCII) مشخصGIF89a یا GIF87a آغاز شوند٬ و یا فایلهایPDF باید با کد %PDF آغاز شوند. این کدها همانطور که گفته شد باید در ابتدای دادههای سازنده آن فایل آورده شوند.
برای بکارگیری این تکنیک باید ابتدا یک ارجاع دهنده برای فایل بسازیم:
$fileinfo = finfo_open(FILEINF_MIME_TYPE);
این ارجاع دهنده در اصل مرجعی برای دستیابی به اطلاعات فایل بر اساس نوع داده شده است (در داخل پرانتز).
بعد باید تابع دیگری برای فراهم کردن منابع فایل و مرجع آن فراخوانی شود:
finfo_file($fileinfo, $filename);
همانطور که مشاهده میکنید این تابع دو ورودی میگیرد٬ مرجع فایل و نام فایل ارسال شده٬ در آخر هم این تابع نوع فایل را بر اساس همان کاراکترهای جادویی باز میگرداند. در پایان کار باید این مرجع را بست:
finfo_close($fileinfo);
اگر در خاطر دارید در درس ارسال فایل٬ فایل مورد نظر را با نوعهایی که تعیین کردیم٬ مقایسه و اگر همخوانی داشت اجازه انتقال دادیم. خب٬ در آن مثال نوع فایل را از طریق اطلاعات MIME یا همان اطلاعات داده شده توسط مرورگر بطور مستقیم گرفتیم و بعد آن اطلاعات (نوع فایل و ...) را با متغییری که انواع مورد اجازه ما برای ارسال بودند در داخل یک ifمقایسه کردیم. حال به سراغ برگه ارسال رفته و بجای استفاده مستقیم از نوع فایل به طریقMIME اطلاعات را به شیوهای که امروز گفتیم گرفته و بعد باقی ماجرا را انجام دهید.
$filename = $_FILES['upload']['tmp_name']
$fileinfo = finfo_open(FILEINFO_MIME_TYPE);
$type = finfo_file($fileinfo, $filename);
$allowed = …
if (in_array($type, $allowed)) …
.
finfo_close($fileinfo);
فکر میکنیم با این اشاره٬ حال خود شما از پس این مهم برآیید. فقط یادتان نرود که آخر کار مرجع را ببندید.
جلوگیری از حملههای XSS(حمله اسکریپتی)
این حمله زمانی اتفاق میافتد که کاربر تارنما بجای نوشتن مشخصات درست خود در فرم ثبت نام٬ اقدام به گذاشتن کدهای اچتیامال یا از آن بدتر کدهای جاوا اسکریپت کند. خب٬ وقتی دادههای ارسالی از فرم ثبت نام به پایگاه دادهها رسید٬ بعد از ذخیره شدن قابل اجرا خواهد بود و تخریبهای زیادی از تغییر کدهای اچتیامال که به بهم ریختگی نمای تارنما ختم میشود٬ تا دزدیدن کوکیها منجر گردد.
پیاچپی توابعی معرفی کرده است که با استفاده از آن میتوان جلوی این حملهها را گرفت. شیوه عملکرد این توابع به این شکل است که٬ آنها ابتدا کدها را شناسایی کرده و بعد کدهای اسکریپتی و قابل اجرا را با کدهای غیر قابل اجرا تعویض میکند.
:htmlspecialchars() این تابع کاراکترهایی ویژهای را که در داخل اسکریپتها استفاده میشوند را با عناصر اچتیامال غیر قابل اجرا عوض میکند. مثلن بجای& عبارت & و یا بجای “ از" استفاده میکند.
:htmlentities() این تابع هم تمام کاراکترهای اجرایی را با کاراکترهای غیر اجرایی عوض میکند.
:strip_tags() این تابع تمام برچسبهای اچتیامال و پیاچپی را پاک میکند.
کاربرد توابع تغییر دهنده کاراکترها
استفاده از این توابع بسیار ساده است٬ کافیست که هر کدام از ورودیهای کادرهای فرم خود را ابتدا از داخل این توابع گذر دهید٬ بطور مثال:
$name = htmlspecialchars ( $_POST[‘name’] ) ;
$subject = htmlentities ($_POST[‘subject’] ) ;
$comment = strip_tags ($_POST[‘comment’] ) ;
البته محل کاربرد این توابع به نوع کاربردی آنها بستگی دارد. مثلا اگر بخواهید که از هک شدن مرورگر و یا از تخریب نمای تارنما جلوگیری کنید از تابع htmlentities() استفاده کنید. مورد استفاده این تابع به تعریف آن نیز بر میگردد: این تابع تمام کاراکترها را جابجا میکند. نکته مهم و قابل بررسی در اینجا کلمه «همه» است. فراموش نکنیم که کاراکترها در داخل URL از کدهای اسکیASCII استفاده میکنند. و اگر در مورد این کدها کمی تحقیق کنیم٬ میبینیم که این کدها فقط توانایی خواندن کاراکترهای انگلیسی را دارند. پس اگر یک تارنمایی که به زبان پارسی است از تابعhtmlentities()٬ بهره ببرد٬ با مشکل خوانش کاراکترهای غیر پارسی بر خواهد خورد. یادتان نرود که حتما از کدگذاری UTF8 در بالای برگه استفاده میکند٬ چرا که این نوع کدگذاری شیوه کار توابع را هم کمی تغییر میدهد.
پس در نتیجه اگر میخواهید تنها بعضی از کاراکترها را از نظر اچتیامال امن کنید کافیست که ازhtmlspecialchars استفاده کنید٬ در مقابل اگر قصد دارید کاراکترهای دیگر هم با توجه به نوع کدگذاری برگه در حالت درست و صحیح آنها در کدگذاری مخصوص اچتیامال نمایش داده شوند٬ ازhtmlentities استفاده کنید.
اگر هنوز موضوع برایتان روشن نشده باید بگوییم که بهتر است یکم بیشتر در مورد این توابع٬ بطور اختصاصی مطالعه بفرمایید.
فیلتر کردن ورودیها توسط تابع filter_var()
یکی دیگر از تکنیکهای امن سازی تارنما از طریق مراقبت ورودیها٬ فیلتر کردن آنها است. در تکنیک ارزیابی دادههای ورودی به این نکته اشاره شد که همیشه باید نسبت به دادههایی که توسط کاربران ارسال میشود٬ حساسیت به خرج داد. این مهم را با بررسی دادههای ارسالی و چند فن دیگر انجام دادیم. در اینجا میخواهیم یک روند دیگر یعنی فیلتر کردن از طریق تابع filter_var() را به ساختار امنیت تارنما اضافه کنیم.
Filter_var ( متغییر ورودی , فیلتر مورد استفاده , انتخابهای دیگر ) ;
همانطور که مشاهده میکنید٬ این تابع سه پارامتر به عنوان ورودی دریافت میکند( دو ورودی اصلی و یک انتخابی). پارامتر ابتدایی٬ متغییری است شامل داده ارسال شده توسط کاربر٬ که میخواهیم آن را بررسی کنیم. پارامتر دوم٬ نوع فیلتری است که برای این متغییر استفاده میشود (این فیلترها بصورت ثابتها constant نوشته میشوند) و پارامتر سوم٬ انتخابهای دیگری برای افزودن معیارهای فیلترینگ است.
فیلترهای مورد استفاده
بطور کلی فیلترها را به دو قسمت ارزیابی یا VALIDATEو پاک کردن٬ زدودن یاSANITIZE تقسیم میکنیم.
فیلترهای ارزیاب VALIDATE
انواع فیلترهای ارزیاب برای استفاده کردن در این تابع عبارتند از:
FILTER_VALIDATE_BOOLEAN
FILTER_VALIDATE_FLOAT
FILTER_VALIDATE_INT
FILTER_VALIDATE_EMAIL
FILTER_VALIDATE_IP
FILTER_VALIDATE_URL
FILTER_VALIDATE_REGEXP
این نوع فیلترها همان طور که از نامهایشان پیداست٬ بررسی میکنند که آیا متغییر آمده به عنوان پارامتر ابتدایی با فیلتر همخوانی دارد یا نه؟ یعنی اینکه آیا داده داخل متغییر با نوع معرفی شده با فیلتر یکی است؟
بطور مثال:
If ( filter_var ( $variable, FILTER_VALIDATE_INT, array ( ‘min_range’ => 1 , ‘max_range’ => 50 ) )
این شرطی با استفاده از تابع فیلتر کردن٬ بررسی میکند که آیا ورودی متغییر یک عدد صحیح بین ۱ و ۵۰ هست یا نه.
قسمت
array ( ‘min_range’ => 1 , ‘max_range’ => 50 )
را به عنوان پارامتر انتخابی برای گذاشتن معیار بیشتر در فیلتر کردن ورودی گذاشتهایم.
فیلترهای پاک کننده SANITIZE
انواع فیلترهای پاککننده برای استفاده کردن در این تابع عبارتند از:
FILTER_SANITIZE_EMAIL
FILTER_SANITIZE_URL
FILTER_SANITIZE_STRING
FILTER_SANITIZE_ENCODED
FILTER_SANITIZE_NUMBER_INT
FILTER_SANITIZE_NUMBER_FLOAT
این نوع فیلترها با توجه به نوع فیلتر داده ورودی را از کاراکترهای غیر قابل قبول در آن فیلتر پاک سازی میکنند.
filter_var ( $url , FILTER_SANITIZE_URL);
این فیلتر ورودی را نسبت به فیلترURL بررسی میکند و اگر کاراکتری که نباید در آدرس بیاید٬ بیابد٬ آن را پاک میکند.
در توضیح فیلتر کردن به همین اندازه بسنده میکنیم٬ فقط یادتان نرود که برای استفاده درست از این تکنیکها باید هر کدام را بطور مجزا و اختصاصی مورد آزمایش قرار دهید تا با چگونگی و نحوه عملکرد آن بیشتر آشنا شوید.
جلوگیری از نفوذ به پایگاه دادهها
یک راه دیگر برای حمله به تارنما٬ استفاده از پرسوجو query که کاربر برای حمله به پایگاه مینویسد. این حمله به این صورت انجام میشود که کاربر بجای دادههای صحیح کادر مورد نظر یک کدی وارد سیستم میکند که بجای پرسوجوی اصلی مینشیند. اثرات خطرناک این عمل اینست که این کد وارد پایگاه دادهها شده و بر اساس هدف نویسنده کد اقدام به تغییر یا تخریب آن میکند.
برای جلوگیری از این حمله از یک روش بسیار ساده بهره میبریم که روند ذخیره سازی دادهها در پایگاه را تغییر میدهد. به این شیوه استفاده از عبارات آماده شده میگویند.
برای درک بیشتر این شیوه به مثال زیر توجه کنید:
فرض کنید که میخواهید اطلاعاتی مانند: نام٬ فامیل٬ سال تولد و زمان ثبت نام را در داخل پایگاه در زمان ثبت نام کاربر ثبت کنید:
$query = 'INSERT INTO users (first_name, last_name, age, date)
VALUES (?, ?, ?, NOW() ) ' ;
$statement = mysqli_prepare ( $dbc , $query ) ;
mysqli_stmt_bind_param($statement, 'ssis', $ first_name, $ last_name, $ age);
mysqli_stmt_execute($statement);
همانطور که مشاهده میکنید٬ در بخش پرسوجو query در قسمت مقدارها VALUESبجای مقدارهای وارد شده توسط کاربر علامت ؟ را میگذاریم.
بعد با استفاده از تابع :
mysqli_prepare ( $dbc , $query )
پرسوجو را اجرا کرده و در متغییر مرجع $statement قرار میدهیم. تا به اینجا پرسوجو اجرا میشود٬ اما دادهای به پایگاه فرستاده نمیشود. در بخش بعد با استفاده از تابع:mysqli_stmt_bind_param() دادهها را با توجه به نوع آنها به پایگاه میفرستیم.
این تابع به این صورت عمل میکند که پارامترهای آن٬ ابتدا متغییر نگهدارنده پرسوجو است٬ بعد نوعهای هر ورودی را با توجه به نوع ورودی بطور مرتب قرار میدهد. بطور مثال برای نام و نام خانوادگی که رشته هستند از s و برای سال تولد که عدد است از I استفاده میکند. البته سال تولد با توجه به شرکت نکردن در محاسبات ریاضی میتواند از نوع رشته باشد٬ در اینجا فقط بخاطر داشتن یک مثال از آن به عنوان عدد استفاده کردیم.
آخرین مرحله هم اجرای پرسوجو و فرستادن داده است که با تابع:
mysqli_stmt_execute($statement); صورت میپذیرد.
اتفاقی که در زمان استفاده از این شیوه رخ میدهد این است که توابع مورد استفاده در شیوه قدیم جایشان را به توابع تازه میدهند. بطور مثال برای بررسی انجام یا وارد شدن داده در پایگاه از تابع:
mysqli_stmt_affected_rows($statement) == 1
استفاده میکنیم. و همچنین از توابع دیگر برای مقاصد دیگر:
mysqli_stmt_error($statement): این تابع برای نمایش اخطار احتمالی استفاده میشود.
mysqli_stmt_close($statement): این تابع برای بستن ارجاع دهنده یا منبع ساخته شده و دارنده دادهها استفاده میشود.
در درس بعدی به شیوه دیگری از ارزیابی دادههای ورودی به نام «عبارات منظم» میپردازیم.
اگر قبلا در بیان ثبت نام کرده اید لطفا ابتدا وارد شوید، در غیر این صورت می توانید ثبت نام کنید.