Cookie، Session و Token چیست و چه تفاوتی دارند؟
کوکی، نشست سمتسرور و توکن/JWT را مفهومی مقایسه کنید: Set-Cookie، HttpOnly، Secure، SameSite و انتخاب معماری بدون شعار «JWT همیشه بهتر است».
سا
11 دقیقه مطالعهسهیل ابراهیمپور
بنیانگذار و مهندس محصول

HTTP بهصورت پیشفرض بدون حالت است: هر درخواست میتواند از دید سرور «آشنایی جدید» باشد. برای اینکه فروشگاه سبد خرید را یادش بماند یا پنل بداند شما همان کاربر لاگینشده هستید، باید حالتی جایی ذخیره شود. سه واژهای که در این بحث مدام قاطی میشوند Cookie، Session و Token هستند. یکی مکانیزم حمل در مرورگر است، یکی الگوی نگهداشت حالت روی سرور، و یکی قالب یا مفهوم اعتبارنامهٔ قابلحمل.
طبق راهنمای MDN، کوکی قطعهٔ کوچکی از داده است که سرور برای مرورگر میفرستد؛ مرورگر ممکن است آن را ذخیره کند و در درخواستهای بعدی همان سرور برگرداند. سرور با هدر Set-Cookie کوکی میسازد و مرورگر با هدر Cookie آن را پس میفرستد. Session و Token روی همین زیرساخت یا کنار آن معنا میگیرند — نه اینکه سه فناوری رقیب همسطح باشند.
این متن مرزها را روشن میکند، پرچمهای امنیتی HttpOnly و Secure و SameSite را از MDN میآورد، تفاوت نشست سمتسرور با الگوی توکن/JWT را مفهومی میگوید، و از شعار «JWT همیشه بهتر است» فاصله میگیرد.

پاسخ کوتاه
Cookie ظرف حمل داده روی مرورگر است. Session معمولاً یعنی سرور یک شناسهٔ نشست میسازد، جزئیات کاربر را سمت خودش نگه میدارد، و فقط شناسه را (اغلب داخل کوکی) به کلاینت میدهد. Token معمولاً یعنی اعتبارنامهای که کلاینت نگه میدارد — گاهی JWT امضاشده — و در هدر Authorization یا محل دیگر میفرستد؛ میتواند حالت را کمتر سمت سرور نگه دارد، اما باطلسازی و امنیت حمل را جابهجا میکند.
برای کوکی نشست: HttpOnly تا جاوااسکریپت نخواند، Secure تا فقط روی HTTPS برود، و SameSite مناسب تا ریسک CSRF و نشت بینسایتی کم شود. انتخاب Session در برابر Token به مقیاس، نیاز موبایل/SPA، مدل لغو دسترسی، و بلوغ تیم بستگی دارد — نه به مد روز.
کوکی وسیله است؛ Session و Token دو الگوی رایج برای «بعد از لاگین چطور بفهمیم کیستی» هستند. وسیله را با الگو قاطی نکنید.
Cookie: مکانیزم مرورگر به زبان MDN
MDN سه کاربرد اصلی کوکی را میشمارد: مدیریت نشست (وضعیت ورود، سبد)، شخصیسازی (زبان، تم)، و ردیابی. برای ذخیرهسازی عمومی سمتکلاینت امروز Web Storage و IndexedDB مناسبترند؛ کوکی با هر درخواست مرتبط فرستاده میشود، محدودیت تعداد و اندازه دارد (حدود ۴KB رایج است) و روی اتصال کند هزینه دارد.
عمر کوکی با Expires یا Max-Age تعیین میشود؛ بدون آنها کوکی نشست مرورگر است و با پایان نشست کلاینت پاک میشود — هرچند بعضی مرورگرها با Session Restore ممکن است آن را برگردانند. برای حذف فوری، همان نام/مسیر/دامنه را با Max-Age=0 یا Expires گذشته بفرستید.
HttpOnly، Secure، SameSite
Secure: کوکی فقط روی درخواست HTTPS فرستاده میشود (با استثنای localhost در بیشتر مرورگرها). سایت HTTP نمیتواند کوکی Secure بگذارد. این در برابر شنود مسیر کمک میکند، اما اگر HttpOnly نباشد جاوااسکریپت یا دسترسی دیسک کلاینت همچنان میتواند مقدار را ببیند.
HttpOnly: جاوااسکریپت از طریق Document.cookie به کوکی دسترسی ندارد؛ فقط در درخواست به سرور میرود. برای شناسهٔ نشست تقریباً همیشه باید روشن باشد تا XSS بهسادگی Session را ندزدد. MDN صریحاً میگوید کوکیهای ماندگار وضعیت ورود باید HttpOnly داشته باشند.
SameSite کنترل میکند کوکی در درخواستهای cross-site فرستاده شود یا نه و به حریم خصوصی و کاهش CSRF کمک میکند: Strict فقط همان سایت؛ Lax برای ناوبری سطحبالای امن از سایت دیگر هم؛ None نیازمند Secure است و برای برخی ویجتهای شخصثالث بهکار میرود. اگر SameSite نباشد، بسیاری از مرورگرها رفتار شبیه Lax پیشفرض دارند.
http
Set-Cookie: sessionId=abc; Secure; HttpOnly; SameSite=Lax; Path=/
Session سمتسرور: شناسه در کوکی، داده در سرور
الگوی کلاسیک وب: بعد از لاگین موفق، سرور یک Session ID سختحدسزدنی میسازد، رکورد نشست را در حافظه، دیتابیس یا store مشترک مینویسد، و ID را با Set-Cookie به مرورگر میدهد. درخواست بعدی Cookie را میآورد؛ سرور ID را میخواند و کاربر و نقشها را از store بارگذاری میکند.
مزیت: باطل کردن نشست (Logout، تغییر رمز، تشخیص سرقت) با حذف/بیاعتبار کردن رکورد سرور ساده است. دادهٔ حساس لازم نیست داخل کوکی باشد. هزینه: سرور باید store نشست را مقیاس بدهد؛ در چند نمونهٔ اپلیکیشن به sticky session یا store مشترک نیاز دارید.
MDN یادآوری میکند اگر سایت کاربر را احراز هویت میکند، بهتر است حتی کوکیهای نشست موجود را هنگام احراز هویت دوباره تولید و ارسال کند تا با Session Fixation مقابله شود — مهاجم نباید بتواند یک ID ازپیشکاشته را به قربانی بچسباند.
Token و JWT: اعتبارنامهٔ قابلحمل
در معماریهای API و موبایل/SPA، الگوی رایج این است که بعد از لاگین یک Access Token (و گاهی Refresh Token) به کلاینت داده شود. کلاینت آن را در حافظه، یا با احتیاط در ذخیرهسازی، نگه میدارد و معمولاً با Authorization: Bearer میفرستد. JWT یک قالب رایج است: سه بخش Base64url شامل هدر، ادعاها (claims)، و امضا تا گیرنده بتواند یکپارچگی را بدون تماس همیشه با صادرکننده در هر میکروسرویس بررسی کند — اگر کلیدها درست مدیریت شوند.
توکن «همیشه جایگزین Session» نیست. میتوانید Session ID را هم نوعی opaque token بدانید. تفاوت کلیدی عملی: در JWT خودکفا، لغو فوری سختتر است مگر denylist، عمر کوتاه، یا introspection. در Session کلاسیک، حذف رکورد کافی است. همچنین اگر JWT را در localStorage بگذارید، هر XSS میتواند آن را بخواند — برخلاف کوکی HttpOnly.
چرا «JWT همیشه بهتر است» غلط است
- برای فرمهای سنتی همدامنه، Session کوکیمحور ساده، بالغ، و از نظر لغو قوی است.
- JWT برای عبور بین سرویسها و کلاینتهای غیرمرورگر جذاب است، نه بهعنوان مد حتمی وب.
- اندازهٔ JWT در هر درخواست، پیچیدگی چرخش کلید، و ریسک ذخیرهسازی نادرست هزینهٔ واقعی دارند.
- میتوان ترکیبی کار کرد: Session برای وب، Token برای API موبایل — با سیاست واحد هویت.
جدول مقایسه
| بُعد | Cookie | Session (سمتسرور) | Token / JWT (مفهومی) |
|---|---|---|---|
| نقش اصلی | حمل/ذخیرهٔ کوچک در مرورگر | حالت کاربر روی سرور + ID | اعتبارنامهٔ قابلارائه توسط کلاینت |
| کجا دادهٔ کاربر است؟ | گاهی داخل کوکی (ریسک) | عمدتاً در store سرور | اغلب داخل/کنار توکن یا در سرویس هویت |
| باطلسازی | حذف کوکی کافی نیست اگر سرور نداند | حذف رکورد نشست | عمر کوتاه، denylist، یا چرخش |
| ریسک XSS | بدون HttpOnly خواندنی است | ID در کوکی HttpOnly مقاومتر | اگر در JS قابلخواندن باشد دزدیدنی است |
| ریسک CSRF | کوکی خودکار فرستاده میشود | نیاز SameSite/توکن CSRF | هدر دستی CSRF را کمتر میآورد؛ XSS جداست |
| مقیاس افقی | — | نیاز store مشترک/چسبنده | با JWT خودکفا آسانتر؛ لغو سختتر |
انتخاب عملی برای محصول
اگر اپلیکیشن وب کلاسیک با رندر سرور یا همانسایت ساده دارید: Session سمتسرور + کوکی Secure و HttpOnly و SameSite=Lax (یا Strict برای بخشهای حساس) نقطهٔ شروع معقول است. اگر کلاینتهای متعدد (موبایل، SPA جدا دامنه، سرویسبهسرویس) دارید: لایهٔ Token با عمر کوتاه و Refresh جدا، یا استانداردهایی مثل OAuth/OIDC، منطقیتر است — جزئیات پروتکل را در طراحی Auth جدا کنید.
هرگز رمز عبور یا دادهٔ PII خام را در کوکی نگذارید. شناسهٔ مات که سرور Lookup کند امنتر از جاسازی ادعاهای حساس در کلاینت است. MDN همین احتیاط را در بخش امنیت کوکیها مطرح میکند و به سازوکارهای جایگزین از جمله JWT بهعنوان گزینهٔ بررسی اشاره میکند — نه حکم قطعی.
چکلیست حداقلی امنیت نشست/توکن
- کوکی نشست: Secure + HttpOnly + SameSite مناسب + Path محدود در حد نیاز.
- چرخش Session ID بعد از لاگین موفق.
- عمر نشست و Idle timeout متناسب با حساسیت (بانک ≠ وبلاگ).
- Logout سمت سرور واقعاً نشست را باطل کند.
- اگر JWT: exp کوتاه، aud/iss را اعتبارسنجی، الگوریتم را ثابت، Secret/کلید را از مخزن دور.
- توکن دسترسی را در لاگ و URL ننویسید.
- HTTPS اجباری قبل از تکیه به Secure cookies.
کجا توکن یا شناسه را ذخیره کنیم؟
برای Session ID داخل کوکی HttpOnly و Secure، جاوااسکریپت عمداً به آن دسترسی ندارد؛ این برای وب همدامنه معمولاً مطلوب است. برای SPA که API را روی دامنهٔ دیگر صدا میزند، کوکی نیازمند تنظیم Domain/SameSite/CORS با credentials است و پیچیدگی CSRF برمیگردد. گذاشتن Access Token در حافظهٔ رَم (متغیر جاوااسکریپت) XSS را محدود به طول عمر صفحه میکند ولی با رفرش از بین میرود؛ بنابراین اغلب با Refresh Token در کوکی محدود یا جریان دوبارهٔ لاگین جفت میشود.
localStorage برای توکن دسترسی بلندعمر انتخاب ضعیفی است چون هر اسکریپت همان origin میتواند بخواند. اگر مجبور به الگوی توکن در فرانت شدید، عمر را کوتاه کنید، Refresh را سختگیرانهتر محافظت کنید، و CSP و پاکسازی XSS را جدی بگیرید. هیچ الگوی ذخیرهسازی، جای HTTPS و HttpOnly درست برای کوکی نشست را نمیگیرد.
CSRF و XSS: دو تهدید متفاوت روی یک کوکی
چون مرورگر کوکی را خودکار میفرستد، سایت بد میتواند مرورگر کاربر لاگینشده را وادار به درخواست به سایت شما کند — این هستهٔ CSRF است. SameSite=Lax یا Strict و توکن ضد CSRF در فرمها دفاعهای کلاسیکاند. XSS مسیر دیگری است: اگر اسکریپت مهاجم داخل صفحهٔ شما اجرا شود، میتواند درخواستهای authenticated بسازد حتی با SameSite، و اگر توکن در JS خواندنی باشد آن را هم سرقت کند.
پس hardening کوکی لازم است ولی کافی نیست. دفاع لایهلایه یعنی: کوکی نشست HttpOnly، ورودی/خروجی امن در برابر XSS، SameSite مناسب، و برای عملیات حساس تأیید دوباره. اگر فقط یکی را «درست» کنید و بقیه را رها کنید، مهاجم از در دیگر وارد میشود.
عمر، تمدید، و خروج
نشست بینهایت راحت است و خطرناک. برای پنل مالی Idle timeout کوتاهتر از فروشگاه محتوایی است. Sliding expiration میتواند تجربه را بهتر کند به شرطی که سقف مطلق هم داشته باشید. Logout باید رکورد سرور را باطل کند؛ پاک کردن کوکی فقط در همان مرورگر کافی نیست اگر مهاجم قبلاً ID را دزدیده باشد.
در الگوی JWT، Logout سمت کلاینت توکن را دور میاندازد ولی کپی دزدیدهشده تا exp معتبر میماند مگر denylist یا تغییر نسخهٔ کلید. به همین دلیل Access Token کوتاهعمر + Refresh قابلابطال ترکیب رایجی است — پیچیدهتر از Session یکتکه، اما برای APIهای متعدد منطقی است.
چرخش منظم Refresh و بستن نشستهای دیگر دستگاه بعد از تغییر رمز، از همان خانوادهای است که OWASP در مدیریت نشست توصیه میکند؛ این مقاله جای تکرار کامل آن Cheat Sheet نیست، اما پیوند مفهومی را جدی بگیرید وقتی به لایهٔ Authentication میرسید.
سومشخص، حریم خصوصی، و کوکی رهگیری
MDN بین کاربرد مشروع کوکی شخصثالث (ویجت، تحلیل محدود) و پروفایلسازی ناخواستهٔ رفتار کاربر در چند سایت تمایز میگذارد. مرورگرها بهسمت محدود کردن third-party cookies رفتهاند؛ تکیهٔ محصول به آنها شکننده است. برای حالت لاگین خودتان، اولویت با first-party و حداقل داده است. اگر بنر رضایت کوکی دارید، آن را با معماری واقعی همخوان کنید: اعلام رهگیری بدون توقف رهگیری، هم اعتماد و هم انطباق را خراب میکند.
قانون سادهٔ محصول: هر کوکی را نامگذاری و مستند کنید — نشست، ترجیح، تحلیل، تبلیغ. کوکی نشست را با عمر بلند رهگیری قاطی نکنید. Prefixed cookieها مثل __Host- در MDN لایهٔ دفاعی اضافه برای مرورگرهای پشتیباناند؛ جایگزین طراحی درست SameSite و Domain نیستند، اما برای نشستهای حساس ارزش بررسی دارند.
جمعبندی برای تصمیم
Cookie مکانیزم مرورگر است؛ Session الگوی حالت سرورمحور است؛ Token الگوی اعتبارنامهٔ کلاینتمحور است. بیشتر سیستمهای بالغ ترکیبی از اینها را با مرز مشخص دارند. پرچمهای کوکی را از MDN جدی بگیرید؛ انتخاب JWT را با نیاز لغو، XSS، و تنوع کلاینت بسنجید نه با ترند.
اگر همین هفته یک کار میکنید: در DevTools بخش کوکیهای دامنهٔتان را باز کنید و برای کوکی نشست ببینید HttpOnly و Secure و SameSite چیست. اگر هر سه ضعیفاند، قبل از بازنویسی معماری به JWT، همان را درست کنید — اغلب بازدهی امنیتی بیشتری دارد.
گام بعدی منطقی: جدا کردن Authentication از Authorization، و نگهداشتن Secretها بیرون از فرانت و مخزن عمومی.
منابع و مراجع
- MDN — Using HTTP cookies — https://developer.mozilla.org/en-US/docs/Web/HTTP/Guides/Cookies
- MDN — Set-Cookie header — https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Set-Cookie
اگر بین Session و Token مردد هستید، اول مدل تهدید (XSS، CSRF، سرقت دستگاه، نیاز لغو فوری) را روی کاغذ بنویسید؛ بعد ابزار را انتخاب کنید. برعکس این ترتیب معمولاً به localStorage پر از JWT بدون طرح لغو ختم میشود.
نویسنده
سا
سهیل ابراهیمپور بنیانگذار FutureForge است. روی طراحی محصول، معماری و استقرار نرمافزار سفارشی کار میکند.
یادداشتهای مرتبط
برای انتخاب مسیر فنی پروژهتان کمک میخواهید؟
از مسئله و محدودیتهایتان بگویید؛ اگر بتوانیم همراهیتان کنیم، برای گفتوگو هماهنگ میکنیم.




