منبع اصلی نوشتار زیر در این لینک قرار دارد

جلسات PHP :‌ آره یا نه؟ مساله اینه.

مقدمه
باور کنید دست خودم نبود!!! هدفم هم اصلا خرابکاری نیست. بیشتر آزمایشه و اطلاع رسانی. من چیکار کنم آخه؟ وقتی اینقدر ساده میشه امنیت یه وب سایت رو به مخاطره انداخت! هدف من آموزش این نیست که چطور خرابکاری کنید، هدفم اینه که کمک کنم این مشکل برطرف بشه.
بحث اصلی : جلسات
معمولا جلسات، از اون چیزهاییه که تو تمام زبانهای برنامه نویسی تحت وب استفاده میشه. این جلسات، اطلاعاتی هستن که در طرف سرور ذخیره میشه، ولی کلید اونها در طرف کلاینت. این کلید معمولا یه رشته غیر قابل حدسه و به دو صورت رد و بدل میشه.
روش اول از طریق لینکه، یعنی مثلا یه لینکی داریم به این صورت :


http://example.com/?sessid=zGNQE1DlHGFjDZLEfdeNK3rvRC7

وقتی این درخواست میرسه به PHP (من کاری به بقیه زبانها ندارم) خودش جلسه با این شماره (zGNQE1DlHGFjDZLEfdeNK3rvRC7) رو پیدا میکنه و بارگذاری میکنه. البته اگه باشه. اگه نباشه هم که خیلی ساده چشماشو میبنده و رد میشه. راه دوم اینه که کلید جلسه از طریق کوکی منتقل شه، یه جورایی محبوب تره این روش، علتشم اینه که لینک خراب نمیشه، لزومی هم نداره هر لینکی تو صفحه هست این اطلاعات بهش الصاق بشه. (شما باید وقت اجرا این کلید جلسه رو بگیرید و هر لینکی که خواستید ایجاد کنید اینو به انتهاش اضافه کنید ولی توی روش کوکی چون این اطلاعات با کوکی رد و بدل میشه نیاز نیست.)
اگه به صورت لینک باشه، دیگه میشه گفت CSRF که قبلا دربارش نوشتم پیش نمیاد، اما معایبشو گفتم.

حالا اگه یکی تو یه کامپیوتر دیگه،‌ به هر نحوی به این کلید دست پیدا کنه، در زمانی که شما هنوز آنلاین هستید و جلسه اعتبار داره بیاد و صفحه شما رو،‌ با این کلید باز کنه (یعنی اگه لینکه که با ایجاد لینک شبیه سازی شده و اگه کوکیه با ایجاد کوکی مورد نظر درخواستو شبیه سازی کنه، خیلی ساده میره تو حساب شما! ایجاد کوکی هم با FireBug و FireCookie مثل آب خوردنه!!)
به همین علته که میگن هر وقت از پای صفحه خودتون بلند شدید، حتما logout کنید. فکر نکنید چون پشت کامپیوتر خودتونید همه چی آرومه!! نه، ممکنه همین الان یه نفر جلسه شما رو از اون طرف دنیا دزدیده باشه و داخل صفحه شما شده باشه!! با این logout جلسه تعطیل میشه و کلیدش بی ارزش میشه.و اینطوری اون آقا/خانم دزد،‌با خارج شدن شما،‌ ناکام میمونه، اما اگه اینکارو نکنید ممکنه تا مدتها همچنان فعال باقی باشه.

این که از وسط راه جلسه دزدیده بشه، فقط و فقط یه راه حل داره اونم استفاده از https هستش. یعنی در حالت عادی و غیر https راهی نیست که از دزدیدن کلید در میانه راه جلوگیری کنیم. به عبارتی ISP شما، و تمام کسانی که در مسیر ارتباط شما به سایت قرار گرفتن با یه مانیتورینگ ساده میتونن اطلاعات جلسه رو بدزدن. خوب، اینو میتونید با یه هزینه اضافه امن کنید ولی آیا خطر این دزدیده شدن جلسه فقط همین جاست؟ یعنی اگه جلسه سالم به مقصد رسید :D اونوقت همه چی سر جاشه؟ خوب بالاخره رسیدم به اصل مطلب.

جواب یه نه است. یکم بزرگتر از نه معمولی!! یه سایت معمولی، از یه سرور اشتراکی استفاده میکنه. نمیصرفه برای یه وبلاگ بری و یه VPS بگیری. خوب این یعنی ممکنه روی سرور شما چندین سایت دیگه موجود باشه. حالا یه کاری میکنیم. یه همچین فایل ایجاد میکنیم :

<?php
  var_dump(glob(session_save_path()."/sess_*"));

روی سرورتون آپلود کنید، اجراش کنید و مطمئنا شگفت زده میشید.(فرض بر لینوکسه، واسه ویندوز \ بگذارید.) یه سرور در پیت دارم برای کارهای آزمایشی، اونجا حتی بک تیک هم بازه :)‌ وقتی این فایل روش اجرا شد، ۴ مگا فایل شد!! این یعنی چند تا کلید؟؟؟ خدا تا! فقط اگه روی suexec باشید کار نمیکنه.
یه برنامه نوشتم که کل این فایلها رو یکی یکی بخونه، توی سرور ذخیره کنه .کلی طول کشید!!! انقدر که تا آخرش نرفتم و نصفه کاره لغوش کردم، تازه رسیده بود به ۳۰ درصد فایلها.(تازه بیشتر فایلها هم خالی بود، در حقیقت جلساتی که اصلا اطلاعاتی ذخیره نشده بود)
زنده باد grep. اول گشتم دنبال آدرس ایمیل کلی پیدا کردم. با حال زیاد توش بود. مثلا info@……ir یا آدرسهایی شبیه این. یکی، نام کاربریش هم admin بود و میلشم آدرس سایت داشت.
خوب سوتی داده شده بود. متوجه شدم که فایل مربوط به چه سایتیه، و جالب اینکه زده بودم به خال! جلسه هنوز فعال بود(یا شاید من با دسترسی به فایل باعث شده بودم PHP گول بخوره؟؟)، به راحتی وارد شدم. با CakePHP بود. همین برام کافی بود، اومدم بیرون، تازه مثل یه کاربر خوب دکمه خروج رو زدم. یکی که اون موقع اینجا بود، گفت Screen shot بگیر ولی خوب اصلا هدفم این نیست که ثابت کنم.

همون یکی که اینجا بود میگفت دسترسی خوندن رو برای PHP ببندید یا از suexec استفاده کنید. اولی عملا ممکن نیست، PHP باید این فایلها رو بخونه، اگه نتونه بخونه که جلسه رو از کجا بارگذاری کنه؟؟ دومی خوبه، ایده بدی نیست، یعنی PHP شما تو فضای کاربری شما اجرا میشه، پس فایلها برای دیگران قابل خوندن نیست. اما هم کنده و هم رو ویندوز ممکن نیست (میگم ویندوز به درد نمیخوره!) در ثانی همه که این روش رو نمیپسندن(مثل من!)
حالا چی؟ بریم داد بزنیم سر اونکسی که مدیر این فضاست و سرور رو فروخته؟ نه. دست کم این مشکل به راحتی توی PHP قابل حله. راه حل هم suexec و این چیزها نیست. فقط چند تا چیز رو باید رعایت کرد.

1-
هرگز اطلاعات حساس رو داخل جلسه ذخیره نکنید. حساس اینجا رنج وسیعی داره،‌ من توی اون کاری که کردم ۶۴ تا آدرس ایمیل پیدا کردم (grep گفت،‌من نشمردم :) )،‌ فقط برای حدود ۳۰ درصد فایلها. ایمیل از اون اطلاعات حساسه. آدرس سایت مثل اینکه منو هدایت کرد به هدفم از اطلاعات حساسه (گرچه اگه اونم نبود راحت میتونستم همه سایتها رو که روی سرور بود پیدا کنم) رمز که دیگه واویلا. حتی hash یا رمز گذاری شده هم نباید داخل جلسه ذخیره بشه. چه اشکالی داره اگه فقط id کاربر در دیتابیس ذخیره بشه و بعد فقط با یه کوئری اضافه اطلاعات هر بار از بانک اطلاعاتی خونده بشه؟؟؟
۲-یه امکانی بگذارید که این جلسات بعد از یه مدتی بی استفاده بشن. توی جلسه یه متغیر ذخیره کنید،‌ حاوی آخرین ساعت دسترسی، اگه وقتی دوباره جلسه خواست بارگذاری بشه اون رو چک کنید از مثلا ۱۰ دقیقه بیشتر بود جلسه رو از بین ببرید. PHP اتوماتیک اینکار رو میکنه ولی روی یک سروری دیدم که تنظیم بود روی ۲ ساعت!! نگذاریدش به عهده خود PHP. گاهی هم این کار نمیکنه! چون PHP از طریق آخرین زمان دسترسی میفهمه عمر جلسه چقدره، اگه یکی بیاد و اینو دستکاری کنه چی؟

– این حدس منه، ممکنه درست نباشه، ولی همین که من فایلهای جلسه رو دوباره خوندم تاریخ آخرین دسترسی اونها هم تغییر کرد، پس PHP هم گول خورد. باید امتحانش کنم (ولی قول دادم به خودم که فعلا نه!)
علاوه بر این، میتونید مثلا IP کاربر، User Agent مربوط به مرورگرش (همه اطلاعاتی هستن که توی آرایه _SERVER ذخیره میشن) رو هم توی جلسه ذخیره کنید(البته به صورت رمزگذاری شده که اگه کسی محتوای جلسه رو دید به راحتی نتونه شبیه سازیش کنه، یا اینکه خیلی راحت از md5 استفاده کنید، IP و User Agent و یه عبارت الکی که به صورت ثابت باشه رو به یه رشته تبدیل کنید، بعد md5 اون رشته رو توی جلسه ذخیره کنید، وقت بارگذاری دوباره جلسه، دوباره این رشته رو ایجاد کنید و md5 اونو با اونی که توی جلسه هستش مقایسه کنید، اگه درست نبود جلسه رو از بین ببرید.)
اینجوری جلسه تا حدی امن میشه حتی اگه فایلش توسط دیگران دیده بشه البته اگه شماره ۱ رو رعایت کنید.

۴-شاید ایده بدی نباشه (من نمیپسندم چندان)‌ اطلاعات رو به صورت رمزگذاری شده توی جلسه ذخیره کنید. اطلاعات حساس رو که اصلا تو جلسه نگذارید (مورد ۱ که گفتم) اطلاعات غیر حساس هم رمز گذاری بشه.

۵-حتما قابلیت خروج برای کاربر بگذارید و مدام تو صفحه ترغیبش کنید که کارش تموم شد خارج بشه نه که بروزر رو ببنده.

سه نداره؟ میدونم. راه حل نهایی و بهترین راه حل همین ۳ هستش. استفاده از تابع session_set_save_handler که قصد دارم پست بعدی رو در تکمیل این پست بنویسم و درباره همین تابع باشه.
فعلا کلی کار ریخته رو سرم و همین که نشستم این مسخره بازیها رو انجام دادم و بعدش این پست رو نوشتم خودش کلیه!!

یه نکته هم برای کسانی که سرور ها رو تنظیم میکنن
تو یه بررسی رو چندین و چند سرور یه چیزی متوجه شدم که میتونه خیلی خطرساز بشه :
۱- پوشه پیشفرض برای ذخیره جلسات استفاده شده، یعنی پوشه tmp سیستم عامل (بسته به ویندوز و یا لینوکس این فرق داره)
۲-کاربر خیلی برنامه ها با کاربر PHP یکیه، یا اینکه تو یه Group هستند، مثلا برنامه ای که برای ارسال میل به کار میره. (تو ویندوز که دیگه بدتر، اصولا PHP به کل پوشه دسترسی داره و کاربر و گروه سرش نمیشه )
ربطشو نفهمیدید؟؟؟ برنامه هایی مثل snedmail (یا معادلهاش تو ویندوز)‌ از همین پوشه tmp استفاده میکنن برای ذخیره اتچمنتها، خیلی برنامه های دیگه هم ممکنه اطلاعات حساسی اینجا ذخیره کنن. PHP که به اینجا دسترسی داشته باشه، میتونه به راحتی اطلاعات اونها رو هم بدزده. یعنی کافیه اون فایلی که بالاتر نوشتم یه کم دستکاری بشه تا “همه” فایلها رو نشون بده، نه فقط فایلهای جلسه رو. و این یعنی اینکه اطلاعات به راحتی در دسترس همه هستش.
پیشنهادم اینه که پوشه های آپلود فایل و ذخیره جلسات رو تغییر بدید به یه پوشه اختصاصی که خودتون میسازید، طوری که tmp کاملا بی استفاده بشه برای PHP بعد پوشه tmp رو به صورت خاص برای PHP ممنوع کنید. اگه برنامه های دیگه هم قابلیت تغییر این پوشه رو دارن برای اونها هم عوض کنید این آدرسها رو. اونوقت دیگه هر برنامه دسترسی داره به یه پوشه برای کارهای خودش و دست کم از جانب برنامه های دیگه، خصوصا PHP در خطر نیست. البته، این کار برنامه رو از دست خودش در امان نگه نمیداره و مشکلی که در این پست مطرح شد همچنان به قوت خودش باقیه.
ای کسانی که جوملا نصب میکنید!!! وقت نصب، برنامه تمام تنظیماتی که شما انجام میدید (از اطلاعات دیتابیس گرفته تا کاربر ادمین….)‌ همه توی جلسه ذخیره میشوند و هنگام پایان نصب هم این جلسه رو از بین نمیبره. (نشون به اونکه من خودم تو بررسی های بعدی اون فایل که بالاتر گفتم، یک فایل نصب جوملا هم پیدا کردم که کلی از زمان نصبش گذشته بود ) حتما به هر صورتی که میتونید این جلسه رو از بین ببرید،‌ بهتره کد نصب رو طوری دستکاری کنید که بعد از اتمام کار جلسه کاملا نابود بشه.
– این پست در راستای روشنگری نوشته شده است و نه آموزش خرابکاری یا به لفظ مصطلح اما غلط :‌ هک. شما مسئول کار خودتان هستید و من مسئول کار خودم!
– من عذاب وجدان دارم اساسی، همین که وارد سایت این بنده خدا شدم. نمیدونم چیکار کنم، میل کنم براش توضیح بدم؟ همین که دیدم وارد شد مثل آدمیزاد خروج رو زدم!! ولی ….
– این پست زمانبندی شده هستش، جدید نیست ولی ترجیح دادم بلافاصله منتشر نشه.
– به اون بابا ایمیل زدم و معذرت خواهی کردم، ایمیل زد و گفت ثابت کن :) من طراحیم نقص نداره و یه سری فحش هم پشت سرش…. خوب به هر حال نیازی نیست که ثابت بشه، اصولا مهم هم نیست. الانم با اون فحشها که داد بی حساب شدیم.



برچسب ها : , , , , ,