ویرگول
ورودثبت نام
Armin
Armin
خواندن ۷ دقیقه·۳ سال پیش

کلید ها دست منه، Session در PHP

امروز تصمیم گرفتم توی این پست، یک وقفه ای میون سری پست قبلی بندازم و یه مطلب تخصصی رو منتشر کنم و تصمیم گرفتم در مورد session (سِشِن) توی php صحبت کنم و بگم چی هست و کاربردش چیه و بقیه موارد. سری پست برنامه نویسی و چالش ها رو هم بعد از این و یسری مطالب تخصصی دیگه ادامه میدم.


به صورت کلی توی برنامه نویسی وب و در زمینه ذخیره سازی اطلاعات کاربران به صورت موقت و همچنین مباحث احراز هویت که به همین مبحث ذخیره سازی اطلاعات ربط داره، همیشه بحث و گفتگو هست و وب دولوپرا میان بررسی میکنن که چه نوع روشی از ذخیره سازی دیتا برای چه منظوری مناسب تره. اما منظورم از ذخیره سازی موقت دیتا چیه و چرا این موضوع اینقدر اهمیت داره؟ بذارید با یه مثال براتون توضیح بدم:


فرض کنید شما وارد یک وب سایت فروشگاهی میشید و قصد دارید با وارد کردن username و password خودتون به حساب کاربریتون در اون سایت وارد شید یا اصطلاحا لاگین (login) کنید. توی این قسمت های لاگین معمولا اکثر سایت ها گزینه ای رو تعبیه میکنن به عنوان "مرا به خاطر بسپار" یا "remember me" که به صورت چک باکس هست و می تونید بنا به خواست خودتون چکش کنید.

یک چک باکس مرا به خاطر بسپار
یک چک باکس مرا به خاطر بسپار


اما این چک باکس چیه و چه کاربردی داره؟ در صورتی که شما این چک باکس رو چک کنید یا به اصطلاح تیک بزنید، اون وب سایت میاد و مشخصات لاگین شمارو سیو می کنه و شما دیگه نیازی نیست برای دفعات بعد یا هر دفعه ای که میخوایید وارد سایت بشید مجددا یوزنیم و پسورد رو بزنید. درواقع به اون وب سایت میفهمونید که من رو به خاطر داشته باش و دفعه بعد از من مشخصات ورود رو نخواه و یا به اصطلاح من رو authenticate نکن.


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


به صورت کلی دیتا رو میشه در دو سمت سرور و کاربر یا Server side و Client side ذخیره کرد و بهش دسترسی داشت. اما اینا چه فرقی با هم دارن و هرکدوم چه ویژگی هایی دارن؟

توی روش دوم که روش سمت کاربر یا Client side هستش، ما دیتا رو بر روی سیستم کاربر ذخیره می کنیم و هر زمان نیاز داشتیم، مجددا بازیابیش می کنیم. توی سمت کاربر قسمت های زیر برای ذخیره دیتا استفاده میشن:

  • متغیر های جاوا اسکریپت که یک زبان سمت کاربر هست
  • ذخیره در DOM Node
  • درون Web Storage ها که به دو قسمت local storage و session storage تقسیم میشن
  • کش (cache)
  • کوکی های (cookies) و ...

اما توی روش اول که روش سمت سرور یا Server side هست، ما دیتا رو روی سرور ذخیره می کنیم و چیزی رو سمت کاربر ذخیره نمی کنیم (مگر session id یا session token که بعدا دربارش صحبت می کنم. توی این روش به صورت کلی امنیت بیشتر هست، چون همونطور که می دونید زمانی که دیتا سمت کاربر ذخیره میشه، کاربر به دیتا دسترسی داره و میتونه اونو تغییر بده که خب اصلااا چیز جالبی نیست. حالا چرا میگم چیز جالبی نیست؟ به این مثال توجه کنید.

مدرسه من از یک سایت برای مشاهده نمرات، مشاهده وضعیت انضباطی مثل غیبت ها، مشاهده وضعیت شهریه و مشاهده پرونده دانش آموزی استفاده می کنه. توی این سیستم تمامی دانش آموزان یک یوزرنیم و یک پسورد دارن که با استفاده از اون می تونن به حساب خودشون لاگین کنن. یوزنیم کد ملی هر دانش آموز هست و پسورد یک کد تولید شده تصادفی یا random generated code در سمت سرور.

صفحه ورود سایت مدرسه
صفحه ورود سایت مدرسه


خب اینجا شاید با خودتون بگید این سیستم که مشکلی نداره و ایمن هست. تا زمانی که من کد ملی کسیو نداشته باشم نمی تونم به حسابش وارد شم و حتی اگر کد ملیشو هم داشته باشم، اون کده که ترکیب عدد و حروف هست رو ندارم و پس کلا دسترسی ندارم به حسابش و سایت ایمنه.

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

داشبورد سایت
داشبورد سایت


که می بینید بالای صفحه نام و نام خانوادگی نوشته شده و امکانات و دسترسی ای هم که هرکس به حساب کاربریش داره رو نشون دادم با فلش های قرمز و داستان زمانی جالب میشه شما متوجه می شید دیتا شما سمت کاربر و در کوکی ذخیره میشه که با راست کلیک کردن و زدن دکمه inspect تو مرورگر و رفتن به زبانه Applications، از قسمت cookies میشه دیدش.

کوکی لاگین من توی کرورگر
کوکی لاگین من توی کرورگر


حالا اینجارو داشته باش! من میام و از فیلد info مقدار studentID رو که یک عدد هست رو تغییر میدم و مرورگر رو رفرش میکنم. نتیجه اینه?:

تادااا، وارد حساب یه بنده خدایی از یه مدرسه دیگه شدم ??
تادااا، وارد حساب یه بنده خدایی از یه مدرسه دیگه شدم ??


پرونده اش رو هم کامل میشه دید ??
پرونده اش رو هم کامل میشه دید ??


پس دیدیم که ذخیره دیتا سمت کاربر می تونه چه مشکلایی رو به وجود بیاره که یکی از اون ها مشکلات امنیتی هست. (البته اینم بگم ذخیره دیتا سمت کاربر همیشه بد نیست و برای قسمت هایی مثل کانفیگ و تنظیمات حساب کاربری مثل اینکه داشبوردش چه رنگی باشه و ... مشکلی نداره و با تغییرشم خطری سیستم رو تحدید نمیکنه). اگر میخوایین بیشتر در مورد این نوع آسیب پذیری بدونید، در مورد cookie injection بخونید.



حالا راه حل چیه؟ اینجاست که زبان ها و پلتفرم های مختلف سمت سرور امکانی رو در اختیار ما میذارن به اسم سشن. یعنی ما میاییم و دیتارو سمت سرور ذخیره می کنیم و هروقت خواستیم بهش دسترسی داریم، و کاربر تنهای دسترسی که به اون دیتا داره id اون سشن هست که یک کد رندوم جنریت هست. مثلا برای php چیزی شبیه به اینه:

سشن آیدی که توی کوکی ها ذخیره میشه
سشن آیدی که توی کوکی ها ذخیره میشه


به صورت کلی توی زبان php وقتی شما یک سایتی که با php نوشته شده رو باز می کنید، اتومات از سرور یک سشن آیدی دریافت می کنید و سرور با اون آیدی شمارو میشناسه. حالا میخوام مثال یک سیستم لاگین که با php کار میکنه رو نشونتون بدم. ابتدا ما یک فایل php داریم که نقش API رو داره و درخواست ها رو مدیریت میکنه و کاربر میتونه ازش برای لاگین استفاده کنه. کد این فایل به شکل زیر هستش:

<?php const USERNAME = 'admin'; const PASSWORD = 'ThisIsMyPassword'; if (isset($_POST[&quotusername&quot]) && isset($_POST[&quotpassword&quot])) { if ($_POST[&quotusername&quot] === USERNAME && $_POST[&quotpassword&quot] === PASSWORD) { echo '{&quotstatus&quot: &quotsuccess&quot, &quotmessage&quot: &quotLogin successful&quot}'; } else { echo '{&quotstatus&quot: &quoterror&quot, &quotmessage&quot: &quotLogin failed&quot}'; } } else { echo '{&quotstatus&quot: &quoterror&quot, &quotmessage&quot: &quotMissing username or password&quot}'; } ?>


توی این کد، ما یوزنیم رو برابر با 'admin' و پسورد رو برابر با 'ThisIsMyPassword' قرار دادیم و گفتیم اگر کاربر این مشخصات (credential) رو برای احرازهویت (authentication) وارد کرد، بهش بگو درسته و در غیر این صورت نذاره لاگین کنه. همونطور که میبینید اگه بهش مشخصات اشتباهی بفرستیم، اینو میگه:

میبینید که توی پاسخ بهمون میگه لاگین نادرسته
میبینید که توی پاسخ بهمون میگه لاگین نادرسته


و اگه مشخصات درست بفرستیم:

لاگین موفقیت آمیز بوده
لاگین موفقیت آمیز بوده


من یک فایل به اسم index.php طراحی میکنم که چک کنه اگر کاربر وارد شده، بهش خوش آمد بگه و اگر وارد نشده، بهش صفحه لاگین رو نشون بده:

فرم لاگین برای ورود
فرم لاگین برای ورود


می بینید که لاگین چطور کار می کنه:

ورود به وب سایت
ورود به وب سایت


اینجا می بینید که لاگین درست کار می کنه، اما یک مشکل داره، وقتی صفحه reload یا refresh میشه مجددا باید لاگین کرد. برای این کار میریم سراغ استفاده از سشن. ابتدا توی هر دو صفحه بالای بالا بعد از باز گردن تگ php دستور زیر رو می نویسیم:

session_start();

و برای ذخیره کاربر اونجایی که لاگین موفق بود میگیم:

$_SESSION[&quotusername&quot] = $_POST[&quotusername&quot];

و برای چک کردن از این کد استفاده می کنیم:

<?php if (isset($_SESSION[&quotusername&quot])) { echo ' $(&quot#form&quot).hide(); (&quot<h1>Hello ' . $_SESSION[&quotusername&quot] . '</h1>&quot); '; } else{ echo ' $(&quot#form&quot).show(); alert(&quotPlease login&quot); '; } ?>

و خروجی این شکلیه:

صفحه لاگین
صفحه لاگین


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


پس فهمیدیم اگر اول کد تابع session_start رو صدا بزنیم، میتونیم دیتا هارو درون متغیر $_SESSION ذخیره کنیم و ازشون استفاده کنیم.


امیدوارم از این پست لذت برده باشید و کارآمد باشه. اگه سورس کدهاش رو میخوایید تا بهتر متوجه بشید از رپو گیتاهبم می تونید دریافتش کنید. اگه نظری دارید مطرحش کنید خوشحالم میشم و سعی میکنم تا جایی که بشه جواب بدم. توی قسمت بعدم معلوم نیست یه مطلب تخصصی دیگه باشه یا ادامه سری قبلی ?. بعدا تصمیم می گیرم. پس تا پست بعد: شاد باشید ??

برنامه نویسیبرنامه نویسی phpphpامنیت
آرمین ام، یه برنامه نویس که عاشق علمه و اگه پیش بیاد زندگی رو هم دوست داره.
شاید از این پست‌ها خوشتان بیاید