Gytyonline
مديريت كل انجمنها
پست: 899
عضو شده در: 14 شهریور 1384
محل سکونت: tehran
امتياز: 8184
|
عنوان: امنیت در تابع include در php |
|
|
سلام
بعد از گذاشتن 2 آموزش مفید و بسیار خوب در مورد توابع include و require توسط حمید عزیز یعنی فرق include و require و توضیح include_once و require_once در زبان PHP و مباحث حرفهای تغییر basedir در include کردن در زبان PHP و همینطور href در HTML و همین طور تاپیکی که قبلا نوشته بودم در اینجا گفتم بد نیست که یکسری توضیح و تجربههای خودم را در مورد امنیت در استفاده از این توابع و طریق درست استفاده از آنها در اینجا مطرح کنم تا این آموزشها کامل تر شوند.
حتما به همان دلایلی که قبلا ذکر شده است شما هم بارها و بارها از این توابع در اسکریپتهای خود استفاده کردهاید مثلا برای وارد کردن هدر یا فوتر برای سایر صفحات اما همیشه استفاده از این توابع توسط برنامه نویس نمیباشد و در برخی موارد مثلا انتخاب کردن زبان سایت یا انتخاب قالب توسط کاربر از این توابع استفاده میشود به عنوان مثال در اسکریپت خود مینویسیم:
کد: |
include("language/".$lang.""); |
که متغییر $lan توسط کاربر توسط یک combo box مشخص میشه و به عنوان مثال یکی از مقادیر farsi.php و یا english.php را برای متغییر $lan برنامه نویس در نظر میگیرد و توسط فرمی فرستاده میشود سمت سرور و در نهایت فایل درستور include خواهد شد:
کد: |
include("language/farsi.php");
or
include("language/english.php"); |
و در شاخه language یکی از دو فایل farsi.php و یا english.php انتخاب خواهد شد و در ظاهر همه چیز درست به نظر میرسد و همه چیز امن اگر این چنین فکر میکنید باید بگم که در اشتباه هستید اگر باور نمیکنید به نکتههای زیر توجه کنید:
فکر کنید به جای اینکه فایلهای زبان سایت در یک شاخه جدا بودن در شاخه اصلی کنار بقیه فایلها بودن و یا اینکه کنار فایلهای زبان سایت فایلهای دیگهای هم وجود داشتن که توسط نرمافزارهایی کاربر میتوانند لیست کامل فایلها و شاخههای موجود بر روی هاست شما را بدست آورد حال کافی میباشد که کاربر خودش یک فرم ایجاد کند و به سرور و آدرس مشخص شده ارسال نمایید و به جای اینکه یکی از دو متغییر farsi.php و یا english.php فرستاده بشود برای متغییر $lan اسم یکی دیگر از فایلهای موجود را برای این متغییر ارسال خواهد کرد فایلهای مهمی در همان شاخه و به همین راحتی به آنها دسترسی پیدا کند نه تنها فایل php بلکه سایر فایلها چون اسم فایل و پسوند آن توسط کاربر مشخص میگردد!!
خوب حالا شاید بگید خوب رفع این مشکل کار چندانی نخواهد برد و به راحتی قابل حل خواهد بود به این صورت که ما پسوند فایل رو خودمان تعیین میکنیم یعنی مینویسیم:
کد: |
include("language/".$lan.".php"); |
و به این ترتیب کاربر فقط میتونه فایلهایی با پسوند php را اجرا نماید و برای اینکه نتواند بقیه فایلها را اجرا کند این فایلها را داخل شاخهی جدا قرار خواهیم داد مثلا داخل شاخه Language که فقط شامل 2 فایل زبان سایت یعنی farsi.php و english.php میباشد و مشکلات حل خواهد شد به همین راحتی و موقع ارسال فرم هم برای متغییر $lan مقادیر farsi و english را تعیین خواهیم کرد که فقط اسم فایل فرستاده شود.
اما واقع با این کار دیگه مشکلی وجود نداره و این تابع امن خواهد بود؟!
اگر جواب شما بله میباشد باز در اشتباه هستید! خوب بیاید دقیقتر شویم بر روی موضوع.
ما مقادیر farsi و english رو فقط فرستادیم و پسوند هم که از قبل تعیین شده پس مشکل کجاس؟ شاید در اینجا ما بتوانیم فایلها را جدا کنیم اما در مواقعی که نتوانیم فایلهای مورد نظر رو از سایر فایلها جدا کنیم چه طور؟
حالا بگذارید باز هم دقیقتر شویم به نظر شما اگر در همه حالات فایلها را در شاخهای جدا قرار دهیم کاربر دیگر نمیتواند سایر فایلها را اجرا نماید؟
اگر جواب شما نمیتواند است باز هم در اشتباه هستید
به نظرتان اگر کاربر بهجای مقادیر farsi و یا english مقداری زیرکی بخرج دهد و عباراتی مثل زیر را وارد نماید چه خواهد شد؟ عبارتی مانند:
کد: |
.../.../.../.../.../.../.../.../.../page |
نظرتان چیست؟ ( کلمه page نام یکی از فایلها دلخواه با پسوند php میباشد) به این ترتیب کاربر میتونه با عبارت .../ بین شاخههای هاست شما حرکت رو به عقب داشته باشد و و یا با بدست آوردن نام شاخهها و فایلهای هاست شما حرکت رو به جلو داشته باشد به این صورت که با تعدادی .../ به شاخه اصلی یعنی root خواهد رسید و بعد از آن آدرس دلخواه خود را وارد میکند و به راحتی در بین شاخههای سایت شما حرکت خواهد کرد!!! و حتی میتواند به فایلهای بسیار مهم و حیاتی هاست شما مانند config و یا passwd که در سی پنل موجود است دسترسی پیدا کند و .... اما خوب شما ممکنه بگید فقط میتونه به فایلهایی با پسوند php دسترسی پیدا کند نه هر فایل دلخواهی مثل passwd و غیره ولی باز هم در اشتباه هستید!! میپرسید چطور؟ به راحتی هر چه تمام تر مسلما میدانید که php بر اساس زبان سی نوشته شده است و خیلی از توابع این دو زبان هم دقیقا مثل هم هستند و حتی کاربردهایشان حالا میخواهم شما را به کلاس برنامه نویسی مقدماتی توی دانشگاه ببرم که تقریبا بیشتر رشتههای فنی داشته اند اگر یادتان باشد در مبحث آرایهها وقتی استادتان به شما این مبحث را آموزش میداد گفته بود که آخرین خانه از آرایه با عبارت \0 و یا همان نال بایت پرخواهد شد و هیچ مقدار دیگری را نخواهد پذیرفت و برنامه وقتی به این عبارت برسد خواهد فهمید که آرایه به انتها رسیده و آن تمام شده است و دیگر ادامه نخواد داد حالا کافی است کاربر ما در اسکریپت نوشته شده توسط ما از این ترفند استفاده نماید یعنی توسط یک کد هگز که به صورت %00 خواهد بود کل روال کار ما را عوض کند یعنی مقدار فرستاده شده به صورت زیر باشد:
کد: |
include("language../../../../../../../../../passwd%00.php"); |
حال دیگر پسوندی را که ما در ادامه رشته قرار دادهایم خوانده نخواهد شد مثل اینکه اصلا .php وجود ندارد و کاربر قادر خواهد بود هر فایل را در هر شاخهای و با هر پسوندی include نمایید !!!
جالب بود نه؟ دقت کنید که تعداد .../ ها اصلا مهم نیست چون به هر مقداری هم که باشد و کاربر خواهد عقب برود از root عقبتر نمیتواند برود و از آنجا میتواند آدرس دلخواه خود را وارد نماید.
. یا حتی ممکن است کاربر از این فرا تر برود مثلا یک فایلی را بر روی سایت شما آپلود نماید یک فایل مخرب و ان را اجرا نماید مثلا در قسمت آپلود آواتار اگر مسائل ایمنی رعایت نشود کاربر همچین فایلی را آپلود خواهد کرد shell.php.jpg خوب سایز فایل کمتر از حد مجاز است پس موردی ندارد پسوند فایل jpg میباشد پس فایل آپلود خواهد شد اما چون عکس حقیقی نیست نمایش داده نمیشود و این اصلا مهم نیست برای کاربر خوب حالا کاربر آدرس آواتارها بر روی سایت شما را دارد محلی که آواتارها آپود میشود و با استفاده از ترفندی که گفتم یعنی %00 آدرس را به این صورت وارد میکند:
کد: |
include("language../../../../../../../../../AVATARADDRESS/shell.php%00.jpg.".php"); |
و دیگه کلا هاست در اختیار کاربر و هکر محترم قرار خواهد گرفت
پس دیدی که استفاده نا مناسب و اشتباه ممکنه چه خطرات زیان باری را داشته باشد.
اما خوب حالا واقعا بهترین و امنترین راه حل برای استفاده از این تابع چیست؟ در این جور مواقع چه کاری انجام دهیم؟
بهترین راه حل استفاده از آرایهها میباشد به این صورت که ما آرایه ای به شکل زیر تعریف خواهیم کرد:
کد: |
$language = Array("farsi","english"); |
که داریم $language[0]=farsi و $language[1]=english و مقداری را که کاربر فرستاده است با این دو خانه از آرایه مقایسه خواهیم کرد اگر مقدار آن دقیقا برابر بود با farsi و یا دقیقا برابر بود با english خواهیم نوشت:
کد: |
if($lan=="farsi")
include("language/farsi.php");
else if($lan=="english")
include("language/english.php"); |
راه حل دیگری که میتوان از آن استفاده کرد مخصوصا برای جلوگیری از کاراکترهای غیر مجاز مثل نال بایت استفاده از عبارات منظم میباشد.
خوب با استفاده و رعایت موارد گفته شد در بالا اسکریپت ما امن خواهد شد و کاربر قطعا دیگر نمیتواند فایل دیگری را اجرا نماید. برای انتخاب قالب نیز میتوان از همین روش استفاده کرد.
امیدوارم این آموزش بدردتان خورده باشد.
اگر جایی از آموزش مشکلی داشت و یا موارد دیگری برای تکمیل تر شدن آموزش به نظرتان رسید خوشحال خواهم شد که برایم ارسال نمایید.
موفق باشید.
امین شفیعی؛ |
|