کار با Session در فلسک
کار با Session در فلسک
مفاهیم پایه و چرایی استفاده از Session
در دنیای توسعه وب مدرن، یکی از چالشهای اساسی که برنامهنویسان همواره با آن دستوپنج نرم میکنند، ماهیت «بیوضعیت» (Stateless) پروتکل HTTP است. به زبان ساده، سرور وب به صورت پیشفرض هیچ خاطرهای ندارد. وقتی کاربر درخواستی را به سرور ارسال میکند، سرور آن درخواست را پردازش کرده و پاسخ را برمیگرداند، اما بلافاصله ارتباط بین آنها قطع میشود و سرور فراموش میکند که چه کسی درخواست را ارسال کرده بود. برای یک تازهکار که تازه پا به عرصه توسعه وب گذاشته است، این سوال پیش میآید که چگونه وبسایتهایی مثل فروشگاههای اینترنتی یا شبکههای اجتماعی میدانند که ما چه کسی هستیم، چه محصولی را به سبد خرید اضافه کردهایم یا اینکه آیا قبلاً وارد حساب کاربری خود شدهایم یا خیر؟
پاسخ به این سوال در مفهومی به نام «مدیریت نشست» یا Session Management نهفته است. Session در واقع مکانیزمی است که به سرور اجازه میدهد اطلاعات خاصی را مربوط به یک کاربر خاص، برای مدت زمان مشخصی در حافظه نگه دارد. تصور کنید که شما وارد یک هتل شدهاید و پذیرش به شما یک کلید میدهد. این کلید به شما اجازه میدهد تا اتاق مخصوص خودتان را پیدا کنید و وسایل شخصیتان را در آنجا بگذارید. هر بار که به هتل برمیگردید، با نشان دادن همان کلید، پذیرش میداند که شما مهمان اتاق شماره فلان هستید. در وب، Session نقش همان کلید و اتاق را بازی میکند. وقتی کاربر وارد سایت میشود، سرور یک شناسه منحصربهفرد (Session ID) برای او ایجاد میکند و این شناسه را معمولاً به صورت یک کوکی (Cookie) در مرورگر کاربر ذخیره میکند. با هر درخواست بعدی، مرورگر این کوکی را به سرور میفرستد و سرور با استفاده از آن، اطلاعات مربوط به همان کاربر را از حافظه بازیابی میکند.
استفاده از Session در فریمورک فلسک (Flask) و به طور کلی در اپلیکیشنهای وب، برای سناریوهای متعددی ضروری است. مهمترین مورد، احراز هویت و ورود کاربران (Authentication) است. وقتی شما نام کاربری و رمز عبور خود را وارد میکنید، سرور پس از تایید صحت اطلاعات، یک Session ایجاد میکند و در آن مثلاً شناسه کاربری شما یا وضعیت «لاگین بودن» را ذخیره میکند. پس از آن، شما نیازی نیست در هر صفحه رمز عبور خود را دوباره وارد کنید؛ چون سرور با بررسی Session شما، هویتتان را تایید میکند. کاربرد دیگر، سبد خرید در فروشگاههاست. شما ممکن است دهها صفحه را در فروشگاه مرور کنید و چندین محصول را انتخاب کنید. Session به شما اجازه میدهد تا لیست محصولات انتخابی را در طول بازدیدهای مختلف از صفحات سایت حفظ کنید تا نهایتاً در یکجا خرید خود را نهایی کنید. همچنین، Session برای ذخیره تنظیمات موقت کاربر، پیامهای خطا یا موفقیت (Flash Messages) و پیگیری رفتار کاربر در سایت نیز استفاده میشود. بدون وجود Session، تعاملات پیچیده و شخصیسازی شده با کاربر در وب تقریباً غیرممکن بود.
مسائل فنی و نحوه پیادهسازی در فلسک
فلسک (Flask) به عنوان یک میکرو-فریمورک، ابزار بسیار قدرتمند و در عین حال سادهای برای کار با Session در اختیار توسعهدهندگان قرار میدهد. برخلاف برخی فریمورکهای سنگین که ممکن است پیکربندیهای پیچیدهای داشته باشند، فلسک از یک دیکشنری (Dictionary) ساده برای دسترسی به دادههای Session استفاده میکند که بسیار شبیه به شیء request است. اما قبل از اینکه بتوانیم از این قابلیت استفاده کنیم، باید یک پیشنیاز بسیار مهم را پیکربندی کنیم و آن «کلید مخفی» یا SECRET_KEY است.
در فلسک، دادههای Session به صورت پیشفرض به صورت رمزنگاری شده (Signed) در مرورگر کاربر (داخل کوکی) ذخیره میشوند. این یعنی سرور به جای اینکه اطلاعات Session را در دیتابیس یا فایلی روی سرور ذخیره کند، آنها را رمزگذاری کرده و به کاربر میفرستد. وقتی کاربر درخواستی ارسال میکند، فلسک این کوکی را میگیرد، با استفاده از SECRET_KEY آن را رمزگشایی میکند و از صحت آن اطمینان حاصل میکند. اگر این کلید تنظیم نشده باشد، فلسک اجازه استفاده از Session را نمیدهد چون نمیتواند امنیت دادهها را تضمین کند. تنظیم این کلید بسیار ساده است و باید یک رشته تصادفی و پیچیده باشد که هیچکس جز شما آن را نمیداند.
برای شروع کار با Session، ابتدا باید آبجکت session را از ماژول flask ایمپورت کنیم. سپس در برنامه خود، میتوانیم مانند یک دیکشنری معمولی پایتون به آن مقدار دهیم یا از آن بخوانیم. برای مثال، برای ذخیره نام کاربری در Session، مینویسیم session['username'] = 'ali' و برای خواندن آن از session.get('username') استفاده میکنیم. استفاده از متد get بهتر است چون اگر کلید مورد نظر وجود نداشت، برنامه با خطا مواجه نمیشود.
یکی دیگر از مسائل فنی مهم، مدیریت عمر Session است. به صورت پیشفرض، Session در فلسک تا زمانی که مرورگر کاربر بسته شود، باقی میماند (Permanent Session نیست). اما اگر بخواهیم Session را برای مدت زمان مشخصی (مثلاً ۲۴ ساعت یا یک هفته) نگه داریم تا کاربر حتی پس از بستن مرورگر هم لاگین باقی بماند، باید ویژگی permanent را روی True تنظیم کنیم و مدت زمان اعتبار آن را در تنظیمات فلسک (PERMANENT_SESSION_LIFETIME) مشخص نماییم. این قابلیت برای سایتهایی که گزینه «مرا به خاطر بسپار» دارند، بسیار حیاتی است.
مثال عملی: پیادهسازی یک سیستم شمارنده بازدید
برای درک بهتر موضوع، بیایید یک مثال ساده اما کاربردی را با هم کدنویسی کنیم. فرض کنید میخواهیم یک صفحه بسازیم که تعداد دفعاتی که یک کاربر خاص آن صفحه را مشاهده کرده است را بشمارد. اگر از Session استفاده نکنیم، سرور نمیتواند تشخیص دهد که بازدید فعلی توسط همان کاربر قبلی است یا یک کاربر جدید. اما با Session، میتوانیم یک شمارنده برای هر کاربر در مرورگرش ذخیره کنیم.
در کد زیر، ابتدا کتابخانههای لازم را ایمپورت میکنیم و کلید مخفی را تنظیم میکنیم. سپس یک مسیر (Route) تعریف میکنیم که در آن ابتدا بررسی میکنیم آیا کلیدی به نام visits در Session وجود دارد یا خیر. اگر وجود نداشت، آن را با مقدار صفر ایجاد میکنیم. سپس مقدار آن را یکی افزایش میدهیم و نتیجه را به کاربر نمایش میدهیم.
from flask import Flask, session, redirect, url_for, escape, request
from datetime import timedelta
app = Flask(__name__)
# تنظیم کلید مخفی برای رمزنگاری Session
app.secret_key = 'a_very_secret_key_that_only_you_know'
# تنظیم مدت زمان اعتبار Session (مثلاً 5 دقیقه برای تست)
app.permanent_session_lifetime = timedelta(minutes=5)
@app.route('/')
def index():
# بررسی وجود کلید 'visits' در Session
if 'visits' in session:
session['visits'] = session['visits'] + 1
else:
session['visits'] = 1
return f"شما این صفحه را {session['visits']} بار بازدید کردهاید."
@app.route('/login')
def login():
# فعال کردن حالت دائمی برای Session
session['username'] = 'user1'
session.permanent = True
return 'شما وارد سیستم شدید.'
@app.route('/logout')
def logout():
# حذف تمام دادههای Session
session.pop('username', None)
return 'شما از سیستم خارج شدید.'
if __name__ == '__main__':
app.run(debug=True)
در این مثال، اگر شما مرورگر خود را رفرش کنید، عدد بازدیدها افزایش مییابد. اما اگر مرورگر را کاملاً ببندید و دوباره باز کنید (و حالت permanent را فعال نکرده باشید)، شمارنده از سر گرفته میشود. همچنین در مسیر /login نحوه ذخیره اطلاعات کاربر و در مسیر /logout نحوه حذف آن با استفاده از متد pop نشان داده شده است.
ملاحظات امنیتی بسیار مهم
کار با Session اگرچه بسیار راحت است، اما اگر با بیدقتی و رعایت نکردن اصول امنیتی انجام شود، میتواند درهای بزرگی را به روی مهاجمان باز کند. اولین و مهمترین نکته امنیتی، همان SECRET_KEY است. این کلید باید کاملاً تصادفی، طولانی و غیرقابل حدس باشد. اگر مهاجم بتواند کلید مخفی شما را پیدا کند، میتواند Sessionهای جعلی تولید کند و هویت هر کاربری را به سرقت ببرد (Session Forgery). هرگز این کلید را در کدهای خود که روی گیتهاب یا مخازن عمومی آپلود میکنید، قرار ندهید و همیشه آن را از متغیرهای محیطی (Environment Variables) بخوانید.
نکته دوم، محدودیت حجم کوکی است. از آنجا که فلسک به صورت پیشفرض دادههای Session را در کوکی مرورگر ذخیره میکند (Client-Side Sessions)، شما نمیتوانید اطلاعات بسیار حجیم را در Session ذخیره کنید. مرورگرها معمولاً محدودیت ۴ کیلوبایتی برای کوکیها دارند. ذخیره کردن اطلاعات زیاد باعث میشود کوکی حذف شود یا برنامه با خطا مواجه شود. بنابراین، فقط اطلاعات ضروری و کوچک مثل شناسه کاربری (User ID) را در Session ذخیره کنید و اطلاعات سنگین را در دیتابیس نگه دارید.
نکته سوم، مربوط به حملات Session Fixation است. اگر کاربری لاگین نکرده باشد، فلسک یک Session خالی برای او میسازد. اگر مهاجم بتواند Session ID یک کاربر قربانی را قبل از لاگین بدزدد و بعد از اینکه کاربر لاگین کرد، از همان Session ID استفاده کند، مهاجم میتواند به حساب کاربر قربانی دسترسی پیدا کند. برای جلوگیری از این امر، بهتر است هنگام لاگین موفقیتآمیز، Session را با استفاده از متدهایی مثل session.regenerate() (در برخی افزونهها) یا با ایجاد یک Session جدید و انتقال دادهها، بهروزرسانی کنید. البته فلسک در نسخههای جدیدتر مکانیزمهای داخلی برای کاهش این ریسک دارد، اما آگاهی از آن ضروری است.
همچنین، همیشه مطمئن شوید که کوکیهای Session شما با پرچم HttpOnly ارسال میشوند تا اسکریپتهای سمت کاربر (JavaScript) نتوانند به محتوای آن دسترسی داشته باشند (جلوگیری از حملات XSS). فلسک به صورت پیشفرض این کار را انجام میدهد. اگر از پروتکل HTTPS استفاده میکنید، حتماً پرچم Secure را برای کوکیها فعال کنید تا کوکیها فقط روی ارتباط امن ارسال شوند و در شبکههای ناامن رهگیری نشوند. در فلسک پیشفرض برنامه httpOnly هست اما جهت اطمینان میتوانید از این کد استفاده کنید:
app.config['SESSION_COOKIE_HTTPONLY'] = True
برای اینکه Secure فعال شود و در واقع اگر سایت بدون ssl/tls باز شد امکان ذخیره سشن وجود نداشته باشد از دستور زیر بهره میگیریم:
app.config['SESSION_COOKIE_SECURE'] = True
تفاوتهای نسخههای فلسک و نکات تکمیلی
فلسک در طول سالها تکامل زیادی یافته است. در نسخههای قدیمیتر فلسک (نسخه ۰.۱۰ و قبل از آن)، نحوه مدیریت Session و الگوریتمهای رمزنگاری ممکن است با نسخههای جدید (نسخه ۱.۰، ۲.۰ و بالاتر) متفاوت باشد. یکی از تغییرات مهم، بهبود الگوریتمهای امضای دیجیتال (Signing) است. در نسخههای جدید، فلسک از کتابخانه itsdangerous با نسخههای بروزتر استفاده میکند که امنیت بیشتری را در برابر حملات برخوردی (Collision Attacks) فراهم میکند.
در نسخههای بسیار جدید فلسک (مثلاً ۲.۳ و بالاتر)، نحوه پیادهسازی Session Interface تغییراتی کرده تا انعطافپذیری بیشتری برای توسعهدهندگان وجود داشته باشد. همچنین، اگر نیاز دارید که دادههای Session را در سمت سرور (Server-Side) ذخیره کنید تا حجم کوکیها کم شود یا امنیت بیشتری داشته باشید، میتوانید از افزونههایی مثل Flask-Session استفاده کنید که دادهها را در فایلهای سیستم، Redis یا دیتابیسهایی مثل MongoDB ذخیره میکند. این افزونه رابط کاربری Session را تغییر نمیدهد و شما همچنان از همان دیکشنری session استفاده میکنید، اما نحوه ذخیرهسازی پشت صحنه تغییر میکند.
در نهایت، توجه داشته باشید که مدیریت صحیح Session یکی از ارکان اصلی توسعه وب اپلیکیشنهای امن است. با رعایت نکات ذکر شده در این مقاله، به ویژه انتخاب یک کلید مخفی قوی و محدود کردن دادههای ذخیره شده در Session، میتوانید اپلیکیشنهایی با فلسک بسازید که هم کارایی بالایی داشته باشند و هم امنیت اطلاعات کاربران را به خوبی تضمین کنند. همیشه مستندات رسمی فلسک را برای آخرین تغییرات و بهترین شیوهها (Best Practices) بررسی کنید، زیرا این فناوری به سرعت در حال پیشرفت است.