اپلیکیشن های تحت وب به طور مکرر از سیشن ها برای ساخت یک محیط قابل تعامل با کاربر استفاده می کنند برای همین موضوع امنیت Session در php بسیار مهم است .
همانطور که میداند HTTP یک پروتکل stateless است , به این معنا که سرور نمی تواند تشخیص دهد که این کاربر از قبل این صفحه وب را مشاهده کرده است و یا اینکه کدام کاربر چه درخواستی را ارسال کرده است .
این قابلیت یک مزیت داشت و آن اینکه دیگر نیازی به ثبت هیچ اطلاعاتی نبود و باعث می شد که انتقال اطلاعات با سرعت بیشتر رد و بدل شود . اما این یکی از ضعف های بزرگ پروتکل http بود که برای مدیریت آن (State Management) باید از روش هایی مثل SESSION و COOKIE ها استفاده می شد .
SESSION چیست ؟
ایده اولیه سیشن ها این بود که سرور یک شناسه id برای ارتباط با کاربر می ساخت , این ID را به مرورگر کاربر ارسال می کرد تا به عنوان شناسه کاربر در یک کوکی ذخیره و در درخواست های بعدی استفاده شود .
روش های بسیار زیادی در وب برای ذخیره سیشن وجود دارد : آرگومان های URL , فیلد های مخفی , دیتابیس , کوکی ها و.. . php از کوکی ها برای ذخیره Session ID ها استفاده می کند . این مقدار کوکی برای هر درخواست فراخوانی می شود . راه دیگر قرار دادن session id در url است . که در اینصورت باید ماژول url rewriting فعال باشد .
پاس دادن مقدار سیشن در آدرس url به هیچ وجه توصیه نمی شود . که در اینصورت با دادن آدرس یک صفحه به یک یوزر دیگر session id کاربر شما به راحتی لو خواهد رفت . استفاده از سیشن در url در جاهایی کاربرد دارد که نشود از کوکی ها استفاده کرد .
قبلا آموزش کار با SESSION در php را آموزش دادیم . پس فقط در این مقاله به امنیت Session در php می پردازیم .
راهکارهای افزایش امنیت Session در php
افزایش امنیت Session در php فقط بخشی از ماجراست . برای افرایش امنیت سیشن باید سه لایه مختلف را امن کنیم .
شبکه > وب سرور > اپلیکیشن تحت وب (PHP)
امنیت سیشن ها در سطح شبکه
همانطور که میدانید پروتکل HTTP تمام درخواست های بین کاربر و سرور را به صورت متن ساده (plain text) رد و بدل می کند . اگر یک هکر به شبکه محلی سرور دسترسی پیدا کند و یا حتی فقط از سرویس های آن شبکه استفاده کند به راحتی می تواند با انجام حملات (Man in the middle) که به مردی در میان معروف است تمام اطلاعات اعم از سیشن و پسورد های وارد شده توسط مدیریت سایت و کاربران و سیشن ها را به راحتی به سرقت ببرد
و خود را به عنوان مدیریت سایت یا یکی از کاربران جا بزند و عملیات مخرب خود را پیاده سازی کند. !
پس سعی کنید از پروتکل HTTP بر روی SSL استفاده کنید که باعث افزودن یک لایه امنیتی به شبکه شما می شود و حتی اگر هکر شبکه شما را اسنیف کند و به سیشن ها و پسورد ها شما دست پیدا کند به هیچ وجه نمی تواند از آن استفاده کنید .
به این دلیل که HTTPS تمام اطلاعات بینن کاربر و سرور را به صورت encrypt شده تبدیل می کند که شکستن آنها با قدرمندترین سرورها ماه ها یا سال ها طول می کشد.!
امنیت سیشن در php
برای افزایش امنیت SESSION در php راهکارهای مختلفی ارایه دادیم که در قالب مثال و معرفی حملات Session Hijacking یا Session Fixation ادامه خواهیم داد.
حملات Session Fixation و Session Hijacking
همیشه سعی کنید مقدار سیشن کاربر را به صورت رندوم و با الگوریتم های غیرقابل بازگشت استفاده کنید (برای آشنایی با الگوریتم های رمزنگاری در php کلیک کنید )تا از حملات SESSION Fixation در امان باشید .
اگر مثلا سیشن کاربر الف را ۱۰۰ و کاربر ب را ۱۵۰ قرار دهید کاربر به راحتی می تواند با انجام چند تست و پیدا کردن الگوریتم نحوه اختصاص دهی مقدار سیشن به کاربر با حملات bruteforce سیشن کاربران دیگر را پیدا کرده و با ست کردن آنها خود را با دسترسی کاربر دیگر وارد سیستم شود . باگی که در قسمت ورود کارمندان سایت همراه اول بود که بعد از گزارش , رفع شد !.
همچنین سعی کنید به هیچ وجه سیشن را به صورت خام در کوکی ها ذخیره نکنید , همیشه آن را به صورت encode شده (SHA-1 , MD5 ,..) ذخیره کنید .
اعتبارسنجی ورودی های کاربر
برای افزایش امنیت Session در php , اگر مقادیر ست شده در سیشن را از طریق ورودی های کاربر دریافت می کنید , حتما کاراکتر های غیر مجاز را با استفاده از توابع htmlspecialchars یا htmlentities پاکسازی کنید .
برای آموزش کامل تابع htmlentities در php کلیک کنید
فکر کنید اگر قصد داشتید این مقادیر را بدون sanitize کردن در دیتابیس ذخیره کنید , کاربر می توانست با اجرای یک دستور sql حمله sql injection را پیاده سازی و دیتابیس شما را هک کند .!
و یا برای مثال اگر مقادیر را مثل اسم کاربر را در سشن دخیره و در جایی مثل پنل مهمان یا هر جایی دیگر که از آن را برای نمایش اسم کاربر استفاده می کردید در اینصورت یک باگ xss را به صورت خودکار در سایت بوجود آوردید که فرد نفوذگر به راحتی می توانست عملیات مخرب خود را برای ربودن سیشن و کوکی کاربر پیاده سازی کند .
ست کردن سشن بر روی IP
یکی از روش های دیگر برای جلوگیری از حملات SESSION Hijacking یا همان دزدیدن سیشن استفاده از ip و user agent مرورگر کاربر در ساخت سیشن است . که در اینصورت اگر حتی session کاربر لو برود یا اسنیف شود چونکه ip پابلیک آنها باهم یکی نیست ,
به هیچ وجه نمی تواند به اطلاعات کاربری دسترسی پیدا کند . البته user agent را می شود با انجام چند تست brute force , useragent کاربر را به راحتی پیدا و ست کند ولی این در مورد ip که یک مقدار منحصر به فرد برای هر کاربر در اینترنت است , جواب نمی دهد
به هر حال کد تشخیص هویت کاربر با useragent و ip به اینصورت است
برای ساخت سیشن کاربر ابتدا از طریق آرایه $_SERVER در php مقادیر ip و عامل کاربری (user-agent) را با md5 اینکد و در متغییر سیشن ذخیره می کنیم
1 2 3 4 5 |
<?php session_stat(); ... $_SESSION['fingerprint'] = md5($_SERVER['HTTP_USER_AGENT'] . PHRASE . $_SERVER['REMOTE_ADDR']); ... |
در این صفحه بررسی می کنیم اگر مقدار هش ip و useragent کاربر با مقدار md5 دخیره شده یکسان است یا نه , اگر نه کاربر با به صفحه دلخواه ریدایرکت می کنیم.
1 2 3 4 5 6 7 |
<?php session_start(); if ($_SESSION['fingerprint'] != md5($_SERVER['HTTP_USER_AGENT'] . PHRASE . $_SERVER['REMOTE_ADDR'])) { session_destroy(); header('Location: http://website login page/'); exit(); } |
بازسازی مقدار session ID
یکی از روش های جلوگیری از حملات session hijacking و افزایش امنیت سشن استفاده از تابع از پیش ساخته (in-built) php به نام session_regenerate_id() در انتهای تمام صفحاتی که به احراز هویت با php نیاز می باشد , است .
Session ID حداقل باید در موارد زیر بازسازی شود:
- زمانی که کاربر وارد میشود (Log in)
- زمانی که کاربر خارج میشود (Log out)
- زمانی که کاربر وارد محیط مدیریتی میشود و یا سطح دسترسی کاربر تغییر میکند
1 2 3 4 |
<?php session_start(); session_regenerate_id(); ?> |
اگر بخواهید session id را در هر مثلا ۱۰۰ درخواست یکبار از اول بسازید می توانید به صورت زیر عمل کنید
1 2 3 4 5 6 7 8 9 10 |
<?php session_start(); //increment and check if ( ++$_SESSION['regenerated_count'] > 100 ) { //reset and regenerate $_SESSION['regenerated_count'] = 0; session_regenerate_id(true); } |
با اینکار در هر بار بازدید کاربر از صفحات سایت یک سیشن جدید ساخته می شود و اگر فردی سیشن قبلی را داشته باشد سریعا دسترسی آن قظع خواهد شد .!
تعیین تاریخ انقضا برای SESSION در php
یکی از روش های دیگر برای افزایش امنیت Session در php تعیین تاریخ انقضا برای سیشن در php با استفاده از تابع time() است که در مقاله زیر به طور کامل موارد استفاده و پیاده سازی آن را توضیح دادیم .
آموزش تعیین تاریخ انقضا برای SESSION در php
امنیت سیشن در php از طریق وب سرور
به طور پیش فرض هر بار کاربری در سیستم لاگین می کند و یک session id به آن اختصاص می یابد این اطلاعات اعم از id سیشن در فولدر /tmp سیستم عامل لینوکس ذخیره می شود .
فولدر tmp در لینوکس یک دایرکتری با پرمیشن ۷۵۵ برای دسترسی کاربران برای ذخیره فایل های خود در آن به صورتی که دیگر کاربران سیستم بتوانند به آن دسترسی پیدا کنند است . اگر از یک هاست اشتراکی استفاده می کنید افراد دیگری که بر روی این سرور هاست دارند می توانند با رجوع به این فولدر به تمام سیشن ها اگر رمزگذاری نشده باشد , دسترسی پیدا کنید
برای تغییر فولدر ذخیره سازی session ها در هاست باید یک سری از تنظیمات خود php.ini را تغییر بدید . اگر دسترسی ندارید می توانید با توابع خود php آن را تغییر بدهید.
تغییر محل ذخیره سازی سیشن ها در سرور
برای اینکار از تابع ini_set به صورت زیر استفاده می کنیم.
1 2 |
<?php ini_set(session.save_path, '/home/user/mysessions'); |
برای دسترسی به اطلاعات در مورد محل ذخیره سازی سیشن ها و همچنین بررسی آن بعد تغییر , پیدا کردن محل فایل php.ini در سرور و دیدن دیگر تنظیمات و ماژول ها مربوط از تابع phpinfo() استفاده کنید
ست کردن فلگ httponly
اگر فلگ httpOnly برای کوکی ها ست شده باشد , در اینصورت حتی با آسیب پذیر بودن سایت شما به باگ xss , هکر نمی تواند با استفاده از زبان های اسکریپت نویسی سمت کاربر مثل جاواسکریپت به کوکی های ذخیره شده در مرورگر دسترسی پیدا کند .
1 2 3 4 5 6 |
<?php session_start(); session_regenerate_id(); // setting ini rule ini_set('session.cookie_httponly', true); ?> |
همچنین دو مورد بالا (محل ذخیره سازی سیشن ها در سرور و ست کردن تاریخ انقضای سیشن) را از طریق فایل php.ini در سرور اختصاصی و یا هاست خود به صورت همیشگی ست کنید تا نیازی به تغییر کدهای php نباشد .
1 2 |
session.save_path = "c:/wamp/tmp" (where the sessions will be saved) session.gc_maxlifetime = 1440 (maximum time session will be alive) |
راه هایی مثل ذخیره سیشن در دیتابیس mysql است که توصیه می شود حتی برای امنیت استفاده نشود چراکه باعث کند شدن صفحات وب سایت شما می شود و همچنین اگر ورودی های کاربر به درستی فیلتر نشده باشد امکان دارد خطراتی را برای لو رفتن کل اطلاعات دیتابیس شما به حملات sql injection بوجود آورد .
همانطور که دیدید امنیت Session در php یک دید کلی بر روی هر سه لایه شبکه , وب سرور و php را میطلبد و به هیچ عنوان فقط بستگی به کد نویسی شما ندارد و کارهایی تکنیکالی برای ایمن سازی سیشن ها به دلیل نبودن زیرساخت صحیح http که در بالا اشاره کردم , می طلبد .
ولی تمام سعیم را کردم که تمام موارد را پوشش دهم تا شما توسعه دهنده وب , امنیت سیشن و کوکی های خود را در حد بالا افزایش دهید .
زمان زیادی صرف تهیه و نوشتن آموزش امنیت Session در php شده است , پس امیدوارم مفید بوده باشد.
اگر نظر یا سوالی در مورد هر یک از بخش های مورد نظر داشتید از قسمت نظرات اقدام کنید , سریعا پاسخگوی سوالات شما هستیم .
موفق و پیروز باشید
دمت گرم
سلام مهندس شفیعی عزیز وقت بخیر
یه بار گفتید از الگوریتم های غیر قابل بازگشت استفاده کنیم و یه بار encode کنیم برای سشنی به اسم key با مقدار value میشه دوتاش رو مثال بزنید کنار هم
استفاده کنیم
سپاس از نت پارادیس
سلام. ممنون.
الگوریتم های غیرقابل بازگشت مثل md5 یا sha12 و غیره هستند که توابع آن در php وجود دارد
سلام مهندس شفیعی گل خداقوت
یه سوال کلی در خصوص امنیت پنل ادمین
آیا هر کاری که به لحاظ امنیتی برای قسمت عمومی سایت انجام میدهیم برای پنل ادمین هم با همون کیفیت انجام بدیم ؟
از این نظر عرض میکنم چون در هاست سی پنل میتونیم برای پوشه ادمین رمز قرار بدیم و آیا این رمز عبور میتونه ما رو از یکسری ملاحظات امنیتی برای پنل ادمین بی نیاز کنه
یا اینکه این رمز هم میتونه توسط هکر بدست بیاد
سلام بله هرجایی از سایتتون باید اعمال کنید
بله میتونه رمز رو پیدا کنه و باید پنل مدیریت رو مخفی کنید روی لاگین کپچای گوگل بزارید
سلام
اگر نام کاربری کاربر داخل یک session ذخیره کنم و مواقع که بخوام اطلاعات خاصی از اون کاربر داخل دیتابیس ذخیره کنم نیاز به اون session دارم چرا که باید مشخص بشه اون اطلاعات مربوط به کدوم کاربر هست حالا صرف اینکه session ایجاد و فراخوانی کنم باز امکان دسترسی هکر به session هست
البته این بگم session امنیتی که ساخت بر مبنا ip و نوع سیستم و تاریخ روز که در هر صفحه با session کاربر بررسی میشه و در صورت اینکه session از کاربر دزدید بشه بازم قابل استفاده نیست
سلام مهندس شفیعی مقاله خوبی بود چند تا سوال
یک
وقتی از سشن استفاده میکنیم تو قسمت کوکی مقدارش به صورت کد شده هست چرا باید از الگوریتم رمزنگاری استفاده کنیم ؟
دو
من بعد از لاگین شدن کاربر وقتی میخواد یه پست رو ویرایش کنه id پست موردنظر رو در یک سشن ذخیره میکنم تا در صفحه ویرایش بهش دسترسی داشته باشم و اطلاعات پست رو به کاربر نشون بدم وقتی بخوام مقدار این سشن رو رمزگذاری کنم چطور به id دسترسی پیدا کنم ؟
سه
اگر کاربر یک هکر باشه و به مقدار ای سشن دسترسی پیدا کنه میتونه همه پست های دیتابیس رو ویرایش کنه ؟
راهنمایی لطفا
سلام.
۱٫اگر بصورت رمزنگاری باشه حتی اگر از طریق سرور به مقدار سشن ذخیره شده دسترسی داشته باشه نمیتونه بعنوان همان کاربر داخل سیستم لاگین شه
۲٫ برای اینکار از متد های گت یا پست استفاده کنید.
۳٫ بله به راحتی میتونه اینکارو انجام بده
با سلام و درود بر شما ،
من یه سشن به نام altuser دارم که آی دی کاربر رو توش ذخیره میکنم و کوکی رو هم با همون سشن ست میکنم
میخواستم بدونم که هکر میتونه سشن altuser رو با مقادیر دلخواهش توی سایت من ست کنه ؟
از ssl هم استفاده میکنم.
ممنون میشم پاسخ بدید .
سلام. خیر. وقتی سشن رو ست می کنید نباید داخل کوکی همان مقدار رو قرار بدید.
اگر هم اصرار به ذخیره در کوکی دارید. آیدی کاربر رو هم باید داخل کوکی کد کنید
بسیار ممنون از آموزش خوبتون آقای شفیعی
یک سوال داشتم
من در صفحه لاگین وقتی که کاربر لاگین میشود یک سیشن با نام کاربری، کاربر می سازم
و با همون سیشن کاربر با دیتابیس کار میکنه
آیا این مشکل امنیتی داره ؟
مثلا اینجا یکی میتونه یکی از سیشن های کاربر دیگر رو به خودش اختصاص بده؟
و در مورد ip و useragent اگر کاربر از یک wifi استفاده کند اینجا دیگر ip یونیک نیست و کس دیگر هم میتونه اون ip رو داشته باشه الان مشکل امنیتی نخواهیم داشت؟
سلام.خوشحالیم که مفید واقع شده.
نه مشکلی پیش نمیاد و از همین روش میتونید استفاده کنید
سلام . مرسی از مطلبتون . این مطالب به آپدیت شدن احتیاج نداره به نظرتون یه اینکه شما خودتون این کار رو انجام میدید؟
با تشکر
سلام. خوشحالیم که مفید واقع شده.
تمام راهکارهای ارایه شده قابل استفاده است و برای بعضی موارد که گفته شده باید دسترسی بالاتری روی سرور داشته باشید مثلا از سرورهای مجازی یا اختصاصی استفاده کنید و امکان اعمال تغییرات روی هاست اشتراکی وجود ندارد.
موفق باشید.
سلام ببخشید من وقتی از این کد ini_set(‘session.cookie_httponly’, true); استفاده میکنم خطا داره برنامه
میتونم برای کوکی ها از
setcookie(“expirecookie”, $time , time() + 900, “/”,NULL, NULL, TRUE);
استفاده کنم ؟ منظورم نوشتن TRUE هست
سلام.
طبق داکیومنت بله امکانش هست :
https://www.php.net/manual/en/function.setcookie.php
موفق باشید.
سلام وقت بخیر
ببخشید من یک فولدر به نام test در مسیر ریشه اصلی سایت ایجاد کردم و میخواستم سیشن ها در این فولدر ذخیره کنم . اما نمیشه !!!
من این کد در صفحه اصلی index ابتدای کد ها قرار میدهم
ini_set(session.save_path, ‘test’);
لطفا راهنمایی میکنید ممنون
سلام. ممنون.
در ابتدا باید آدرس را بصورت مطلق (absolute) وارد کنید تا مشکلی پیش نیاد (فولدر test را باید از قبل ساخته باشید)
ini_set(session.save_path, ‘/home/user/public_html/test’);
که در بالا میتونید به جای /home/user/public_html/ از ثابت هایی مثل DOCUMENT_ROOT برای دریافت مسیر اصلی روی هاست استفاده کنید
همچنین برای امنیت همیشه بهتر است که سیشن خارج از فولدر قابل دسترس از طریق url یعنی قبل از public_html قرار بگیرد (در پنل های مختلف این public_html با نام های www یا httpdocs شناخته می شود)
مورد بعدی هم اینکه چون این تابع متغییر های محیطی php که در php.ini هستند را تغییر می دهد و یک مورد امنیتی هست بیشتر هاستینگ ها این قابلیت ساخت و تغییر ini سفارشی را در اختیار مشتریان هاست اشتراکی قرار نمی دهند که از هاستینگ هم میتونید بپرسید.
موفق باشید.
ممنون از پاسختون یعنی بهتر است من یک پوشه قبل از پوشه اصلی سایت مثلا httpdocs ایجاد کنم ؟
خواهش می کنم.
بله
عالی بود مرسی از اموزشتون
سلام. خوشحالم که مفید واقع شده . موفق باشید
عاااااالي واقعا هم مطالب سايتتون عاليه هم اينكه كامل توضيح ميدين با مثال و اينكه از عكسهاي جالب هم استفاده ميكنين،باشد كه توي هممممه مراحل زندگيتون موفق باشين
سلام . ممنون خوشحالم که مورد رضایت شما دوست عزیز قرار گرفته . همچنین همیشه موفق و پیروز باشید.
سلام خسته نباشيد
يكي از بحث هاي امنيتي آپلود عكس يا فايل توسط كاربر هستش
خيلي تو نت مي گردم ولي هر راهكاري يه روش گرد كردن توسط هكر داره
تو سامانه من وقتي كاربر عكسي آپلود مي كنه تو كل سيستم مي چرخه
نمي تونم با ايزوله كردن فولدر آپلود حل كنم
حتما بايد فايل تميز وارد سيستم بشه
راهكاري برأي چك كردن فايل وجود داره؟
سلام . ممنونم .
بله کافیه یک آرایه از mime-type های قابل قبول مثلا برای تصویر image/jpeg , image/png و .. تعریف کنید و بعد با in_array کنترل کنید که البته به تنهایی نباید استفاده بشه چون با افزونه هایی مثل live http header و یا tamper data قابل دور زدنه.
مرحله دوم چک کردن پسوند فایل است که با تابع pathinfo باید چک کنید.
و مرحله سوم چک کردن یک سری از کد ها مثلا
سلام مجدد
اگر ما آدرسی مانند https://example.com/test.php?color=red باز کنیم با توجه به اینکه دامنه از ssl استفاده میکنه پس باید رمزگذاری انجام بشه ولی ما در سمت سرور به راحتی با آرایه $_GET به دادههایی که در کوئری استرینگ ست میشن دسترسی داریم.
پس باید نتیجه این باشه که ssl دادههای کوئری استرینگو رمزنگاری نمیکنه درسته؟
ممنون.
سلام .
اطلاعات در URLرو شما میتونید با روش های دیگه ای مثل اینکودینگ های مختلف امن نگه دارید ولی همانطور که می دونید به هیچ وجه نباید اطلاعات حساس مثل پسورد ها و توکن ها رو در url قرار بدید چرا که ssl در لایه Transport در HTTP کار میکنه و اطلاعات POST رو اینکریپت میکنه و اگر مقدار خاصی در URL پاس نمی دید نیازی به اینکود کردن اونها هم نیست .
موفق باشید.
سلام حسن آقا
مطلبت عالیه خیلی استفاده میکنم از مطالب سایتت.
خدا خیرت بده.
سلام . خوشحالم که مفید واقع شده .
مرسی . موفق و پیروز باشید.
ممنون از مقاله مفیدتون
خواهش می کنم . خیلی خوشحالم که مفید واقع شده .
موفق و پیروز باشید