امروز تصمیم گرفتم توی این پست، یک وقفه ای میون سری پست قبلی بندازم و یه مطلب تخصصی رو منتشر کنم و تصمیم گرفتم در مورد session (سِشِن) توی php صحبت کنم و بگم چی هست و کاربردش چیه و بقیه موارد. سری پست برنامه نویسی و چالش ها رو هم بعد از این و یسری مطالب تخصصی دیگه ادامه میدم.
به صورت کلی توی برنامه نویسی وب و در زمینه ذخیره سازی اطلاعات کاربران به صورت موقت و همچنین مباحث احراز هویت که به همین مبحث ذخیره سازی اطلاعات ربط داره، همیشه بحث و گفتگو هست و وب دولوپرا میان بررسی میکنن که چه نوع روشی از ذخیره سازی دیتا برای چه منظوری مناسب تره. اما منظورم از ذخیره سازی موقت دیتا چیه و چرا این موضوع اینقدر اهمیت داره؟ بذارید با یه مثال براتون توضیح بدم:
فرض کنید شما وارد یک وب سایت فروشگاهی میشید و قصد دارید با وارد کردن username و password خودتون به حساب کاربریتون در اون سایت وارد شید یا اصطلاحا لاگین (login) کنید. توی این قسمت های لاگین معمولا اکثر سایت ها گزینه ای رو تعبیه میکنن به عنوان "مرا به خاطر بسپار" یا "remember me" که به صورت چک باکس هست و می تونید بنا به خواست خودتون چکش کنید.
اما این چک باکس چیه و چه کاربردی داره؟ در صورتی که شما این چک باکس رو چک کنید یا به اصطلاح تیک بزنید، اون وب سایت میاد و مشخصات لاگین شمارو سیو می کنه و شما دیگه نیازی نیست برای دفعات بعد یا هر دفعه ای که میخوایید وارد سایت بشید مجددا یوزنیم و پسورد رو بزنید. درواقع به اون وب سایت میفهمونید که من رو به خاطر داشته باش و دفعه بعد از من مشخصات ورود رو نخواه و یا به اصطلاح من رو authenticate نکن.
خب طبیعتا تا اینجا حدس زدید می خوام راجع به چی صحبت کنم. درواقع اینجا و جاهایی مثل این، این بحث مطرح میشه که دیتا کاربر رو ما به چه صورتی ذخیره کنیم تا بعدا بهش دسترسی داشته باشیم. درواقع به دنبال راهی هستیم تا بهترین جارو برای ذخیره دیتا انتخاب کنیم. اما قبل از هر چیزی باید بررسی کنیم کلا چه جاهایی میشه دیتا رو ذخیره کرد.
به صورت کلی دیتا رو میشه در دو سمت سرور و کاربر یا Server side و Client side ذخیره کرد و بهش دسترسی داشت. اما اینا چه فرقی با هم دارن و هرکدوم چه ویژگی هایی دارن؟
توی روش دوم که روش سمت کاربر یا Client side هستش، ما دیتا رو بر روی سیستم کاربر ذخیره می کنیم و هر زمان نیاز داشتیم، مجددا بازیابیش می کنیم. توی سمت کاربر قسمت های زیر برای ذخیره دیتا استفاده میشن:
اما توی روش اول که روش سمت سرور یا 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["username"]) && isset($_POST["password"])) { if ($_POST["username"] === USERNAME && $_POST["password"] === PASSWORD) { echo '{"status": "success", "message": "Login successful"}'; } else { echo '{"status": "error", "message": "Login failed"}'; } } else { echo '{"status": "error", "message": "Missing username or password"}'; } ?>
توی این کد، ما یوزنیم رو برابر با 'admin' و پسورد رو برابر با 'ThisIsMyPassword' قرار دادیم و گفتیم اگر کاربر این مشخصات (credential) رو برای احرازهویت (authentication) وارد کرد، بهش بگو درسته و در غیر این صورت نذاره لاگین کنه. همونطور که میبینید اگه بهش مشخصات اشتباهی بفرستیم، اینو میگه:
و اگه مشخصات درست بفرستیم:
من یک فایل به اسم index.php طراحی میکنم که چک کنه اگر کاربر وارد شده، بهش خوش آمد بگه و اگر وارد نشده، بهش صفحه لاگین رو نشون بده:
می بینید که لاگین چطور کار می کنه:
اینجا می بینید که لاگین درست کار می کنه، اما یک مشکل داره، وقتی صفحه reload یا refresh میشه مجددا باید لاگین کرد. برای این کار میریم سراغ استفاده از سشن. ابتدا توی هر دو صفحه بالای بالا بعد از باز گردن تگ php دستور زیر رو می نویسیم:
session_start();
و برای ذخیره کاربر اونجایی که لاگین موفق بود میگیم:
$_SESSION["username"] = $_POST["username"];
و برای چک کردن از این کد استفاده می کنیم:
<?php if (isset($_SESSION["username"])) { echo ' $("#form").hide(); ("<h1>Hello ' . $_SESSION["username"] . '</h1>"); '; } else{ echo ' $("#form").show(); alert("Please login"); '; } ?>
و خروجی این شکلیه:
همونطور که می بینید، کاربر وارد سایت شده و با استفاده از سشن دیگه نیازی به لاگین مجدد نیست و تنها کاری که میتونه بکنه، پاک کردن سشن هست که در نتیجش چیز خاصی نمیشه و لاگ اوت اتفاق می افته. (البته این رو بگم که استفاده از سشن به معنی ایمن بود وب سایت نیست و حتی حمله ای هم با نام Session Injection وجود داره که اگر شما وارد سایتی شده باشید و هکر بتونه سشن شمارو سرقت کنه و جای سشن خودش بزنه، می تونه وارد حساب شما بشه که اگر خواستید می تونید راجع بهش بخونید.)
پس فهمیدیم اگر اول کد تابع session_start رو صدا بزنیم، میتونیم دیتا هارو درون متغیر $_SESSION ذخیره کنیم و ازشون استفاده کنیم.
امیدوارم از این پست لذت برده باشید و کارآمد باشه. اگه سورس کدهاش رو میخوایید تا بهتر متوجه بشید از رپو گیتاهبم می تونید دریافتش کنید. اگه نظری دارید مطرحش کنید خوشحالم میشم و سعی میکنم تا جایی که بشه جواب بدم. توی قسمت بعدم معلوم نیست یه مطلب تخصصی دیگه باشه یا ادامه سری قبلی ?. بعدا تصمیم می گیرم. پس تا پست بعد: شاد باشید ??