JWT مخفف عبارت JSON Web Token است و یک استاندارد باز با شماره RFC 7519 محسوب میشود که برای انتقال اطلاعات بهصورت امن و امضاشده (Signed) بین دو طرف طراحی شده است.
به زبان ساده، JWT یک توکن متنی است که پس از ورود موفق کاربر (Login)، توسط سرور تولید شده و در اختیار کلاینت قرار میگیرد. از آن پس، کاربر برای هر درخواست به API این توکن را همراه درخواست ارسال میکند و سرور با بررسی اعتبار آن، هویت کاربر را تأیید یا رد میکند.
برخلاف Session Authentication، در JWT معمولاً نیازی نیست اطلاعات نشست کاربران در حافظه یا پایگاه داده سرور ذخیره شود. به همین دلیل از JWT بهعنوان یک روش Stateless Authentication نیز یاد میشود.
بهعنوان مثال، زمانی که کاربری نام کاربری و رمز عبور خود را وارد میکند، سرور پس از بررسی اطلاعات، یک JWT تولید میکند. این توکن میتواند شامل اطلاعاتی مانند شناسه کاربر، نقش (Role)، زمان انقضا و سایر اطلاعات موردنیاز باشد. کاربر این توکن را در درخواستهای بعدی از طریق هدر Authorization ارسال میکند و سرور بدون نیاز به مراجعه به Session، اعتبار آن را بررسی میکند.
مقدمه
در دنیای امروز، تقریباً هیچ برنامه تحت وب یا اپلیکیشن موبایلی را نمیتوان پیدا کرد که بدون سیستم احراز هویت (Authentication) فعالیت کند. کاربران برای ورود به فروشگاههای اینترنتی، پنلهای مدیریتی، شبکههای اجتماعی، سامانههای بانکی و حتی بازیهای آنلاین ابتدا باید هویت خود را اثبات کنند. اما سؤال اصلی اینجاست که پس از وارد کردن نام کاربری و رمز عبور، چگونه سرور مطمئن میشود که این درخواست واقعاً متعلق به همان کاربر است؟
در گذشته، بیشتر برنامههای تحت وب از Session Authentication استفاده میکردند. در این روش، پس از ورود موفق کاربر، اطلاعات نشست (Session) در حافظه یا پایگاه داده سرور ذخیره میشد و مرورگر تنها شناسه Session را در قالب Cookie ارسال میکرد. هر بار که کاربر صفحهای را باز میکرد، سرور این شناسه را بررسی کرده و در صورت معتبر بودن، اجازه دسترسی صادر میکرد.
با رشد معماریهای مدرن مانند REST API، Microservices، Single Page Application (SPA) و اپلیکیشنهای موبایل، استفاده از Session با چالشهایی مانند مقیاسپذیری، مدیریت Session و هماهنگی بین چندین سرور روبهرو شد. همین موضوع باعث شد روشهای جدیدی برای احراز هویت توسعه پیدا کنند که یکی از محبوبترین و پراستفادهترین آنها JWT Authentication یا احراز هویت مبتنی بر JSON Web Token است.
امروزه بسیاری از فریمورکها و سرویسهای مطرح دنیا مانند ASP.NET Core، Node.js، Spring Boot، Laravel، Django، Express و حتی بسیاری از سرویسهای ابری از JWT برای احراز هویت کاربران استفاده میکنند. دلیل این محبوبیت، سادگی، سرعت، Stateless بودن و قابلیت استفاده در انواع سیستمهای مختلف است.
در این مقاله به صورت کامل با JWT آشنا میشویم، ساختار آن را بررسی میکنیم، نحوه عملکرد آن را قدمبهقدم توضیح میدهیم و مزایا، معایب و نکات امنیتی مهم آن را نیز بررسی خواهیم کرد.
JWT Authentication چیست؟
JWT که مخفف JSON Web Token است، یک استاندارد باز برای انتقال امن اطلاعات بین دو طرف محسوب میشود. این استاندارد در RFC 7519 تعریف شده و هدف اصلی آن انتقال اطلاعاتی است که بتوان به صحت آنها اعتماد کرد.
به زبان ساده، JWT یک رشته متنی رمزنگاریشده نیست، بلکه امضاشده (Signed) است. این رشته شامل اطلاعاتی درباره کاربر یا درخواست است و توسط سرور امضا میشود تا هیچ شخصی نتواند بدون داشتن کلید مخفی، محتوای آن را تغییر دهد.
فرض کنید کاربری وارد یک سایت فروشگاهی میشود و اطلاعات ورود خود را وارد میکند. اگر نام کاربری و رمز عبور صحیح باشد، سرور به جای ذخیره کردن Session، یک Token برای کاربر تولید میکند. این Token به مرورگر یا اپلیکیشن ارسال میشود و از این لحظه به بعد، کاربر در تمامی درخواستهای خود همین Token را همراه درخواست ارسال میکند.
سرور هنگام دریافت Token، ابتدا امضای دیجیتال آن را بررسی میکند. اگر امضا معتبر باشد و Token نیز منقضی نشده باشد، درخواست کاربر معتبر شناخته میشود و نیازی به ورود مجدد وجود ندارد.
همین ویژگی باعث شده JWT به گزینهای ایدهآل برای APIها تبدیل شود، زیرا سرور نیازی به نگهداری اطلاعات Session ندارد و هر درخواست کاملاً مستقل از درخواستهای قبلی بررسی میشود.
چرا JWT به وجود آمد؟
قبل از معرفی JWT، بیشتر وبسایتها از Session Authentication استفاده میکردند. این روش سالها عملکرد مناسبی داشت، اما با رشد سیستمهای توزیعشده مشکلات مختلفی ایجاد شد.
فرض کنید یک وبسایت روی ده سرور مختلف اجرا شده است. اگر Session کاربر روی سرور شماره یک ذخیره شود و درخواست بعدی او به سرور شماره هفت برسد، سرور جدید اطلاعی از Session کاربر نخواهد داشت.
برای حل این مشکل معمولاً از روشهایی مانند:
- Session Replication
- Sticky Session
- Redis Session Storage
- Database Session
استفاده میشود که هرکدام پیچیدگیهای خاص خود را دارند.
در مقابل، JWT هیچ اطلاعاتی روی سرور ذخیره نمیکند. تمام اطلاعات موردنیاز داخل خود Token قرار دارد و هر سروری که کلید امضا را داشته باشد، میتواند اعتبار Token را بررسی کند.
همین ویژگی باعث شده JWT به انتخاب اول بسیاری از پروژههای Cloud و Microservice تبدیل شود.
Authentication چیست؟
یکی از اشتباهات رایج برنامهنویسان تازهکار، یکی دانستن Authentication و Authorization است؛ در حالی که این دو مفهوم کاملاً متفاوت هستند.
Authentication به معنی احراز هویت است.
در این مرحله سیستم بررسی میکند که آیا شما همان شخصی هستید که ادعا میکنید یا خیر.
برای مثال:
- وارد کردن نام کاربری و رمز عبور
- ورود با اثر انگشت
- ورود با تشخیص چهره
- ورود با Google
- ورود با GitHub
- ورود با کد پیامکی
همگی روشهای مختلف Authentication هستند.
اگر اطلاعات صحیح باشد، سیستم هویت شما را تأیید میکند.
Authorization چیست؟
پس از اینکه سیستم مطمئن شد شما چه کسی هستید، نوبت به بررسی سطح دسترسی میرسد.
این مرحله Authorization نام دارد.
برای مثال فرض کنید سه کاربر مختلف در یک سامانه وجود دارند:
- مدیر سایت
- نویسنده
- کاربر عادی
هر سه کاربر میتوانند وارد سیستم شوند، اما سطح دسترسی آنها متفاوت است.
مدیر سایت میتواند:
- حذف کاربران
- مدیریت محصولات
- مشاهده گزارشها
- تنظیمات سایت
را انجام دهد.
در حالی که نویسنده تنها امکان ثبت مقاله را دارد و کاربر عادی فقط میتواند مقالات را مطالعه کند.
بنابراین:
Authentication پاسخ سؤال زیر است:
شما چه کسی هستید؟
اما Authorization پاسخ سؤال زیر را میدهد:
اجازه انجام چه کاری را دارید؟
JWT معمولاً هر دو مفهوم را پوشش میدهد؛ زیرا علاوه بر شناسه کاربر، اطلاعات مربوط به نقش (Role)، سطح دسترسی (Permission) یا سایر اطلاعات موردنیاز نیز داخل Token قرار میگیرد.
JSON Web Token دقیقاً چیست؟
JWT در حقیقت یک رشته متنی است که از سه بخش اصلی تشکیل شده است.
ظاهر یک JWT معمولاً چیزی شبیه نمونه زیر است:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9 . eyJzdWIiOiIxMjM0NTYiLCJuYW1lIjoiQWxpIiwicm9sZSI6IkFkbWluIiwiZXhwIjoxNzY1MjAwMDAwfQ . SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c
اگر به ساختار آن دقت کنید، مشاهده میکنید که Token از سه قسمت تشکیل شده است و هر قسمت توسط یک نقطه (.) از قسمت بعدی جدا شده است.
این سه بخش عبارتاند از:
- Header
- Payload
- Signature
هرکدام از این بخشها وظیفه مشخصی دارند که در ادامه به صورت کامل آنها را بررسی میکنیم.
بخش اول: Header
Header اطلاعات مربوط به Token را نگهداری میکند.
این بخش معمولاً شامل دو مقدار اصلی است:
- نوع Token
- الگوریتم امضا
نمونه Header:
{ "alg": "HS256", "typ": "JWT" }
در این مثال:
- typ مشخص میکند که نوع Token برابر JWT است.
- alg نشان میدهد که برای امضای Token از الگوریتم HS256 استفاده شده است.
الگوریتمهای مختلفی برای امضای JWT وجود دارد که رایجترین آنها عبارتاند از:
- HS256
- HS384
- HS512
- RS256
- ES256
انتخاب الگوریتم مناسب تأثیر مستقیمی بر امنیت سیستم دارد و در بخشهای بعدی مقاله هرکدام را به صورت کامل بررسی خواهیم کرد.
پس از تولید Header، محتوای آن به فرمت JSON تبدیل شده و سپس با الگوریتم Base64Url Encode میشود.
بخش دوم: Payload
Payload مهمترین بخش JWT است.
تمام اطلاعاتی که سرور قصد دارد به کاربر اختصاص دهد، در این قسمت قرار میگیرد.
نمونهای از Payload:
{ "sub":"25", "name":"Hamid Imani", "role":"Admin", "email":"admin@example.com", "exp":1765200000 }
در این مثال اطلاعات زیر داخل Token قرار گرفته است:
- شناسه کاربر
- نام کاربر
- نقش کاربر
- ایمیل
- زمان انقضا
نکته بسیار مهمی که بسیاری از افراد تصور اشتباهی درباره آن دارند این است که Payload رمزنگاری نمیشود.
این بخش فقط Encode میشود؛ بنابراین هر فردی که Token را در اختیار داشته باشد، میتواند اطلاعات داخل آن را مشاهده کند.
به همین دلیل نباید اطلاعات حساسی مانند موارد زیر را داخل JWT ذخیره کنید:
- رمز عبور
- شماره کارت بانکی
- کد ملی
- کلیدهای امنیتی
- اطلاعات محرمانه کاربران
JWT محل ذخیره اطلاعات عمومی یا Claimهایی است که برای احراز هویت و مجوزدهی لازم هستند، نه دادههای محرمانه.
Claim چیست؟
دادههای موجود در Payload با نام Claim شناخته میشوند.
Claim در واقع یک ویژگی یا ادعا درباره کاربر است.
برای مثال:
{ "name":"Hamid", "role":"Admin" }
در اینجا دو Claim وجود دارد:
- name
- role
سیستم هنگام بررسی Token از همین Claimها برای تشخیص هویت و سطح دسترسی استفاده میکند.
Claimها به سه دسته تقسیم میشوند:
Registered Claims
این Claimها توسط استاندارد JWT تعریف شدهاند و هرکدام معنی مشخصی دارند.
مانند:
- iss
- sub
- aud
- exp
- iat
- nbf
- jti
Public Claims
Claimهایی هستند که برنامهنویس تعریف میکند اما بهتر است از نامهای استاندارد استفاده شود تا با سایر سیستمها تداخل ایجاد نشود.
Private Claims
این Claimها فقط داخل همان پروژه استفاده میشوند.
برای مثال:
{ "CustomerId":15, "Plan":"Premium", "IsVIP":true }
این اطلاعات تنها برای همان سیستم معنا دارند.
Signature؛ مهمترین بخش امنیتی JWT
تا اینجا با دو بخش اول JWT یعنی Header و Payload آشنا شدیم. اما هنوز یک سؤال بسیار مهم باقی مانده است:
اگر Payload فقط Encode شده باشد و رمزنگاری نشده باشد، از کجا بفهمیم کسی اطلاعات داخل Token را تغییر نداده است؟
فرض کنید یک کاربر عادی Token زیر را دریافت کرده است:
{ "UserId": 15, "Name": "Hamid", "Role": "User" }
از آنجایی که Payload رمزنگاری نشده است، کاربر میتواند آن را Decode کند و محتوایش را ببیند. حال اگر شخصی مقدار Role را از User به Admin تغییر دهد چه اتفاقی میافتد؟
اگر JWT فقط از Header و Payload تشکیل شده بود، سرور هیچ راهی برای تشخیص این تغییر نداشت و کاربر میتوانست به راحتی دسترسی مدیر سیستم را به دست آورد.
دقیقاً به همین دلیل بخش سوم یعنی Signature ایجاد شده است.
Signature مانند مهر و امضای دیجیتال روی Token عمل میکند. این امضا تضمین میکند که هیچ بخشی از Token پس از تولید توسط سرور تغییر نکرده است. اگر حتی یک حرف از Header یا Payload تغییر کند، Signature دیگر معتبر نخواهد بود و سرور درخواست را رد میکند.
به همین دلیل، امنیت JWT نه به خاطر مخفی بودن اطلاعات داخل آن، بلکه به دلیل غیرقابل جعل بودن امضای دیجیتال آن است.
Signature چگونه ساخته میشود؟
برای ساخت Signature، سرور سه بخش را با هم ترکیب میکند:
- Header Encode شده
- Payload Encode شده
- Secret Key (یا Private Key)
سپس این اطلاعات توسط الگوریتم انتخابشده (مثلاً HS256) هش میشوند.
به صورت مفهومی:
Signature = HMACSHA256( Base64Url(Header) + "." + Base64Url(Payload), SecretKey )
نکته بسیار مهم این است که Secret Key هرگز برای کاربر ارسال نمیشود.
تنها سرور این کلید را در اختیار دارد.
به همین دلیل هیچ شخصی خارج از سرور نمیتواند Signature معتبر تولید کند.
اگر Token دستکاری شود چه اتفاقی میافتد؟
فرض کنید Token اولیه به شکل زیر باشد:
{ "Role":"User" }
هکر آن را تغییر میدهد:
{ "Role":"Admin" }
از آنجا که Signature قبلی براساس مقدار User تولید شده بود، دیگر معتبر نیست.
وقتی Token به سرور ارسال میشود، سرور دوباره Signature را با استفاده از Secret Key محاسبه میکند.
اگر نتیجه با Signature داخل Token یکسان نباشد، سرور بلافاصله درخواست را رد میکند.
معمولاً پاسخ سرور چیزی مانند موارد زیر خواهد بود:
401 Unauthorized
یا
Invalid Token
بنابراین تغییر دادن اطلاعات داخل JWT بدون داشتن Secret Key تقریباً غیرممکن است.
Secret Key چیست؟
Secret Key یکی از مهمترین اجزای سیستم JWT است.
این کلید رشتهای محرمانه است که فقط روی سرور نگهداری میشود.
نمونهای از یک Secret Key ضعیف:
123456
یا
password
این کلیدها به هیچ عنوان مناسب نیستند.
نمونه بهتر:
$2a#kL9mQw!9A@bR73DfLm#2Qx8YzN1Pk
یا حتی رشتهای تصادفی با طول ۲۵۶ بیت که توسط ابزارهای تولید کلید ساخته شده باشد.
اگر Secret Key افشا شود، مهاجم میتواند Tokenهای کاملاً معتبر تولید کند؛ بنابراین نگهداری امن این کلید از مهمترین مسئولیتهای توسعهدهنده است.
فرآیند احراز هویت با JWT چگونه انجام میشود؟
حال که با اجزای JWT آشنا شدیم، بیایید کل فرآیند ورود کاربر را مرحلهبهمرحله بررسی کنیم.
فرض کنید کاربری قصد ورود به یک فروشگاه اینترنتی را دارد.
مرحله اول: ورود اطلاعات
کاربر فرم ورود را تکمیل میکند.
Username : Hamid Password : ********
این اطلاعات از طریق HTTPS به سرور ارسال میشوند.
مرحله دوم: بررسی اطلاعات
سرور اطلاعات را با پایگاه داده مقایسه میکند.
اگر نام کاربری یا رمز عبور اشتباه باشد:
401 Unauthorized
برگردانده میشود.
اگر اطلاعات صحیح باشند، مرحله بعد آغاز میشود.
مرحله سوم: تولید JWT
سرور اطلاعات کاربر را استخراج میکند.
برای مثال:
{ "UserId":15, "Role":"Admin", "Name":"Hamid" }
سپس Header، Payload و Signature را ساخته و JWT تولید میکند.
مرحله چهارم: ارسال Token
سرور Token را به کلاینت برمیگرداند.
نمونه پاسخ:
{ "access_token":"eyJhbGc..." }
مرحله پنجم: ذخیره Token
کلاینت Token را ذخیره میکند.
محل ذخیره میتواند یکی از موارد زیر باشد:
- حافظه برنامه (Memory)
- Cookie
- LocalStorage
- SessionStorage
در بخش امنیتی مقاله بررسی خواهیم کرد که هرکدام چه مزایا و معایبی دارند.
مرحله ششم: ارسال درخواستهای بعدی
اکنون کاربر قصد مشاهده اطلاعات پروفایل خود را دارد.
درخواست HTTP به شکل زیر ارسال میشود:
GET /api/profile Authorization: Bearer eyJhbGc...
عبارت Bearer مشخص میکند که نوع احراز هویت، Bearer Token است.
مرحله هفتم: اعتبارسنجی
سرور مراحل زیر را انجام میدهد:
- بررسی امضا
- بررسی زمان انقضا
- بررسی معتبر بودن الگوریتم
- استخراج Claimها
اگر همه چیز صحیح باشد:
200 OK
برگردانده میشود.
چرا JWT Stateless است؟
یکی از مهمترین مزایای JWT، Stateless بودن آن است.
Stateless یعنی سرور هیچ اطلاعاتی درباره کاربران نگهداری نمیکند.
در سیستم Session وضعیت به شکل زیر است:
User ↓ Server ↓ Session Storage
اما در JWT:
User ↓ JWT ↓ Server
تمام اطلاعات موردنیاز داخل خود Token قرار دارد.
به همین دلیل هر درخواست مستقل از درخواست قبلی بررسی میشود.
مزایای Stateless بودن
Stateless بودن مزایای فراوانی دارد.
مقیاسپذیری بالا
اگر پروژه روی چندین سرور اجرا شود، تمام سرورها میتوانند Token را اعتبارسنجی کنند.
نیازی به اشتراکگذاری Session نیست.
سرعت بیشتر
سرور لازم نیست در هر درخواست به پایگاه داده مراجعه کند تا Session کاربر را پیدا کند.
در بسیاری از موارد تنها بررسی Signature کافی است.
مناسب برای Cloud
در سرویسهای ابری ممکن است درخواستهای کاربر هر بار به یک سرور متفاوت ارسال شوند.
JWT بدون هیچ مشکلی در این شرایط کار میکند.
مناسب برای Microservice
در معماری Microservice دهها سرویس مختلف وجود دارد.
تمام این سرویسها میتوانند Token را بررسی کرده و بدون نیاز به Session، هویت کاربر را تشخیص دهند.
Access Token چیست؟
وقتی درباره JWT صحبت میکنیم، معمولاً منظور همان Access Token است.
Access Token توکنی است که اجازه دسترسی به API را صادر میکند.
برای مثال:
User Login ↓ Access Token ↓ API Access
این Token معمولاً عمر کوتاهی دارد.
مثلاً:
- ۵ دقیقه
- ۱۵ دقیقه
- ۳۰ دقیقه
- ۱ ساعت
دلیل کوتاه بودن عمر آن، افزایش امنیت سیستم است.
اگر مهاجمی به Access Token دست پیدا کند، تنها تا زمان انقضای آن میتواند از آن سوءاستفاده کند.
چرا Access Token کوتاهعمر است؟
فرض کنید عمر Token برابر با یک سال باشد.
اگر Token لو برود، مهاجم تا یک سال به حساب کاربر دسترسی خواهد داشت.
اما اگر Token فقط ۱۵ دقیقه اعتبار داشته باشد، پس از پایان این مدت دیگر قابل استفاده نخواهد بود.
به همین دلیل در اکثر سیستمهای حرفهای، عمر Access Token بسیار کوتاه انتخاب میشود.
Refresh Token چیست؟
اگر Access Token هر ۱۵ دقیقه منقضی شود، آیا کاربر باید هر ۱۵ دقیقه دوباره وارد سیستم شود؟
قطعاً خیر.
برای حل این مشکل از Refresh Token استفاده میشود.
پس از ورود موفق، معمولاً سرور دو Token تولید میکند:
- Access Token
- Refresh Token
Access Token برای دسترسی به API استفاده میشود و Refresh Token تنها برای دریافت Access Token جدید به کار میرود.
Refresh Token معمولاً عمر بسیار طولانیتری دارد؛ مثلاً:
- ۷ روز
- ۳۰ روز
- ۹۰ روز
وقتی Access Token منقضی شود، کلاینت Refresh Token را برای سرور ارسال میکند و در صورت معتبر بودن، سرور یک Access Token جدید صادر میکند؛ بدون اینکه کاربر دوباره نام کاربری و رمز عبور خود را وارد کند.
تفاوت Access Token و Refresh Token
در بخش قبل با مفهوم کلی Access Token و Refresh Token آشنا شدیم، اما برای درک بهتر، بیایید یک سناریوی واقعی را بررسی کنیم.
فرض کنید وارد پنل مدیریت یک فروشگاه اینترنتی شدهاید.
پس از وارد کردن نام کاربری و رمز عبور، سرور دو Token برای شما تولید میکند.
Access Token اعتبار: 15 دقیقه Refresh Token اعتبار: 30 روز
از این لحظه به بعد، تمام درخواستهای شما با Access Token ارسال میشوند.
مثلاً:
- مشاهده محصولات
- ثبت سفارش
- ویرایش پروفایل
- تغییر رمز عبور
همگی از Access Token استفاده میکنند.
حالا فرض کنید بعد از ۱۵ دقیقه همچنان در سایت فعال هستید.
Access Token منقضی میشود.
اگر سیستم فقط از Access Token استفاده میکرد، باید دوباره صفحه Login نمایش داده میشد.
اما در سیستمهای حرفهای این اتفاق نمیافتد.
کلاینت متوجه منقضی شدن Access Token میشود و بدون اینکه کاربر متوجه شود، Refresh Token را برای سرور ارسال میکند.
سرور مراحل زیر را انجام میدهد:
- بررسی معتبر بودن Refresh Token
- بررسی منقضی نشدن آن
- بررسی اینکه این Token قبلاً لغو نشده باشد
- صدور Access Token جدید
کاربر هیچ صفحهای مشاهده نمیکند و همچنان به کار خود ادامه میدهد.
چرا Refresh Token نباید برای دسترسی به API استفاده شود؟
گاهی برنامهنویسان تازهکار تصور میکنند اگر Refresh Token عمر بیشتری دارد، بهتر است مستقیماً از آن برای دسترسی به API استفاده شود.
این کار کاملاً اشتباه است.
Refresh Token تنها یک وظیفه دارد:
دریافت Access Token جدید.
اگر Refresh Token نیز برای دسترسی مستقیم به API استفاده شود، در صورت سرقت آن، مهاجم برای مدت بسیار طولانی به حساب کاربر دسترسی خواهد داشت.
به همین دلیل در اکثر سیستمها Refresh Token فقط روی یک Endpoint خاص مانند زیر پذیرفته میشود:
POST /api/auth/refresh
هیچ Endpoint دیگری نباید Refresh Token را قبول کند.
Claims چیست؟
یکی از مهمترین ویژگیهای JWT، وجود Claimها است.
Claimها اطلاعاتی هستند که درباره کاربر یا Token داخل Payload قرار میگیرند.
به عنوان مثال:
{ "sub":"125", "name":"Hamid", "role":"Admin", "exp":1765200000 }
در این Token چهار Claim وجود دارد.
هر Claim هدف مشخصی دارد.
برخی از آنها توسط استاندارد JWT تعریف شدهاند و برخی دیگر را برنامهنویس ایجاد میکند.
Registered Claims
JWT تعدادی Claim استاندارد معرفی کرده است.
استفاده از این Claimها اجباری نیست، اما تقریباً در تمام پروژههای حرفهای از آنها استفاده میشود.
sub (Subject)
شناسه اصلی کاربر یا موجودیتی که Token برای آن صادر شده است.
نمونه:
{ "sub":"125" }
در بیشتر پروژهها مقدار آن همان UserId است.
exp (Expiration Time)
یکی از مهمترین Claimها است.
مشخص میکند Token تا چه زمانی معتبر خواهد بود.
مثلاً:
{ "exp":1765200000 }
وقتی زمان فعلی از مقدار exp عبور کند، Token دیگر معتبر نیست.
سرور باید بلافاصله آن را رد کند.
iat (Issued At)
زمان صدور Token را مشخص میکند.
مثلاً:
{ "iat":1765100000 }
از این مقدار میتوان برای تحلیل لاگها یا بررسی عمر Token استفاده کرد.
nbf (Not Before)
این Claim مشخص میکند Token از چه زمانی معتبر است.
فرض کنید Token امروز صادر شده اما قرار است از فردا قابل استفاده باشد.
در این صورت قبل از زمان nbf، سرور باید آن را رد کند.
iss (Issuer)
مشخص میکند Token توسط چه سیستمی صادر شده است.
مثلاً:
{ "iss":"ImaniNova" }
اگر مهاجم Token مربوط به سیستم دیگری را ارسال کند، سرور میتواند آن را تشخیص دهد.
aud (Audience)
مشخص میکند Token برای چه سیستمی صادر شده است.
مثلاً:
{ "aud":"ImaniNovaAPI" }
اگر همان Token برای API دیگری ارسال شود، معتبر نخواهد بود.
jti (JWT ID)
شناسه یکتای Token است.
مثلاً:
{ "jti":"3A75C2D7" }
از این مقدار برای جلوگیری از Replay Attack یا لغو Token استفاده میشود.
Private Claims
علاوه بر Claimهای استاندارد، شما میتوانید اطلاعات موردنیاز پروژه خود را نیز داخل JWT قرار دهید.
برای مثال:
{ "UserId":25, "Role":"Admin", "FullName":"Hamid Imani", "Department":"IT", "Plan":"Premium", "Country":"Iran" }
این اطلاعات کاملاً وابسته به پروژه هستند.
آیا میتوان اطلاعات زیادی داخل JWT قرار داد؟
از نظر فنی بله.
اما از نظر طراحی، این کار اشتباه است.
برخی برنامهنویسان تقریباً کل اطلاعات کاربر را داخل Token قرار میدهند.
مثلاً:
- نام
- نام خانوادگی
- آدرس
- شماره تلفن
- تصویر پروفایل
- تنظیمات کاربر
- لیست نقشها
- لیست مجوزها
- تنظیمات پنل
- اطلاعات شرکت
نتیجه چه میشود؟
JWT بسیار بزرگ میشود.
گاهی اندازه آن به چندین کیلوبایت میرسد.
از آنجا که این Token در تمام درخواستها ارسال میشود، حجم ترافیک شبکه افزایش پیدا میکند.
به همین دلیل توصیه میشود تنها اطلاعات ضروری داخل JWT قرار بگیرد.
چه اطلاعاتی نباید داخل JWT ذخیره شود؟
یکی از اشتباهات رایج برنامهنویسان، ذخیره اطلاعات حساس در Payload است.
به خاطر داشته باشید که Payload رمزنگاری نمیشود و هر فردی که Token را در اختیار داشته باشد، میتواند آن را Decode کند.
بنابراین هرگز اطلاعات زیر را داخل JWT قرار ندهید:
- رمز عبور
- رمز دوم
- شماره کارت بانکی
- CVV2
- کد ملی
- شماره شناسنامه
- کلیدهای API
- Secret Key
- اطلاعات پزشکی
- اطلاعات مالی محرمانه
- پاسخ سؤالات امنیتی
JWT برای نگهداری اطلاعات محرمانه طراحی نشده است.
الگوریتمهای امضای JWT
یکی از مهمترین قسمتهای JWT، الگوریتم امضای آن است.
الگوریتم تعیین میکند Signature چگونه ساخته شود.
سه خانواده اصلی الگوریتم وجود دارد.
HS256
محبوبترین الگوریتم JWT است.
در این روش، یک Secret Key بین سرور و فرآیند اعتبارسنجی مشترک است.
همان کلیدی که Token را تولید میکند، برای بررسی اعتبار نیز استفاده میشود.
مزایا:
- بسیار سریع
- ساده
- مناسب اکثر پروژهها
- مصرف منابع کم
معایب:
اگر Secret Key لو برود، مهاجم میتواند Token معتبر تولید کند.
RS256
در پروژههای بزرگ معمولاً از RS256 استفاده میشود.
در این الگوریتم دو کلید وجود دارد.
- Private Key
- Public Key
Private Key فقط روی سرور نگهداری میشود.
Public Key میتواند بین سرویسهای مختلف توزیع شود.
مزیت بزرگ این روش این است که هیچکس با داشتن Public Key نمیتواند Token جدید تولید کند.
فقط اعتبار آن را بررسی میکند.
به همین دلیل RS256 در سیستمهای سازمانی، بانکها و معماری Microservice بسیار محبوب است.
ES256
این الگوریتم از رمزنگاری Elliptic Curve استفاده میکند.
مزیت اصلی آن نسبت به RSA این است که:
- امنیت بالا
- کلیدهای کوچکتر
- سرعت مناسب
- حجم کمتر Token
به همین دلیل در برخی سیستمهای مدرن مورد استفاده قرار میگیرد.
تفاوت HS256 و RS256
اگر پروژه کوچکی دارید و فقط یک سرور مسئول تولید و بررسی Token است، HS256 معمولاً انتخاب مناسبی است.
اما اگر چندین سرویس مختلف نیاز به بررسی Token دارند، یا پروژه شما معماری توزیعشده دارد، RS256 انتخاب بهتری خواهد بود؛ زیرا کلید خصوصی فقط در اختیار سرویس صادرکننده باقی میماند و سایر سرویسها تنها با کلید عمومی اعتبار Token را بررسی میکنند.
JWT چگونه اعتبارسنجی میشود؟
هر بار که کاربر درخواستی به API ارسال میکند، سرور تنها به وجود Token اکتفا نمیکند.
فرآیند اعتبارسنجی معمولاً شامل مراحل زیر است:
-
بررسی وجود Header
Authorization - استخراج Token
- Decode کردن Header و Payload
- بررسی الگوریتم مجاز
- محاسبه مجدد Signature
- مقایسه Signature محاسبهشده با Signature موجود در Token
-
بررسی زمان انقضا (
exp) -
بررسی زمان شروع اعتبار (
nbf) -
بررسی صادرکننده (
iss) -
بررسی مخاطب (
aud) - استخراج Claimها
- اعمال مجوزها بر اساس Role یا Permission
اگر هر یک از این مراحل با شکست مواجه شود، درخواست باید رد شود و معمولاً پاسخ 401 Unauthorized یا در برخی موارد 403 Forbidden بازگردانده میشود.
JWT یا Session Authentication؟ کدام بهتر است؟
یکی از متداولترین سؤالهایی که هنگام طراحی سیستم احراز هویت مطرح میشود این است که آیا بهتر است از JWT Authentication استفاده کنیم یا Session Authentication؟
واقعیت این است که هیچکدام از این دو روش به صورت مطلق بر دیگری برتری ندارد. انتخاب مناسب به نوع پروژه، معماری نرمافزار، تعداد کاربران و نیازهای امنیتی بستگی دارد.
در روش Session Authentication، پس از ورود موفق کاربر، سرور اطلاعات نشست (Session) را در حافظه یا پایگاه داده ذخیره میکند و یک شناسه Session در قالب Cookie به مرورگر ارسال میشود. در هر درخواست بعدی، مرورگر این شناسه را ارسال میکند و سرور با مراجعه به Session ذخیرهشده، هویت کاربر را تشخیص میدهد.
در مقابل، JWT اطلاعات موردنیاز را داخل خود Token قرار میدهد و سرور نیازی به نگهداری Session ندارد. هر درخواست به صورت مستقل اعتبارسنجی میشود و همین ویژگی باعث شده JWT برای REST APIها، اپلیکیشنهای موبایل و معماری Microservice بسیار مناسب باشد.
به طور کلی:
Session Authentication مناسب است برای:
- وبسایتهای سنتی
- پنلهای مدیریتی ساده
- پروژههایی که تنها روی یک یا چند سرور محدود اجرا میشوند
- سیستمهایی که نیاز به لغو فوری Session کاربران دارند
JWT مناسب است برای:
- REST API
- اپلیکیشنهای موبایل
- Single Page Application (SPA)
- معماری Microservice
- سرویسهای Cloud
- سیستمهایی که مقیاسپذیری بالایی نیاز دارند
بهترین محل ذخیره JWT کجاست؟
یکی از مهمترین تصمیمها هنگام استفاده از JWT، انتخاب محل مناسب برای ذخیره Token است.
اشتباه در این بخش میتواند امنیت کل سیستم را تحت تأثیر قرار دهد.
رایجترین گزینهها عبارتاند از:
- LocalStorage
- SessionStorage
- حافظه (Memory)
- HttpOnly Cookie
هر کدام مزایا و معایب خاص خود را دارند.
LocalStorage
LocalStorage یکی از محبوبترین محلهای ذخیره JWT است.
مزایا:
- پیادهسازی ساده
- باقی ماندن Token حتی پس از بسته شدن مرورگر
- دسترسی آسان از طریق JavaScript
اما یک مشکل مهم دارد.
اگر سایت دچار حمله XSS شود، کد مخرب JavaScript میتواند Token را خوانده و برای مهاجم ارسال کند.
به همین دلیل استفاده از LocalStorage در پروژههای حساس باید با احتیاط انجام شود.
SessionStorage
SessionStorage شباهت زیادی به LocalStorage دارد، با این تفاوت که با بسته شدن تب مرورگر، اطلاعات آن حذف میشود.
امنیت آن در برابر XSS تفاوتی با LocalStorage ندارد، زیرا همچنان توسط JavaScript قابل دسترسی است.
Memory
در برخی پروژهها Token فقط داخل حافظه برنامه نگهداری میشود.
مزیت این روش آن است که پس از Refresh شدن صفحه یا بسته شدن برنامه، Token از بین میرود و احتمال سرقت آن کاهش مییابد.
البته کاربر پس از Refresh ممکن است نیاز به دریافت مجدد Access Token از طریق Refresh Token داشته باشد.
HttpOnly Cookie
بسیاری از متخصصان امنیت استفاده از HttpOnly Cookie را برای نگهداری Token توصیه میکنند.
ویژگی مهم HttpOnly این است که JavaScript نمیتواند به آن دسترسی داشته باشد.
در نتیجه حتی اگر سایت دچار حمله XSS شود، مهاجم قادر به خواندن Token نخواهد بود.
البته هنگام استفاده از Cookie باید تنظیمات امنیتی مانند Secure و SameSite نیز به درستی پیکربندی شوند تا احتمال حملات CSRF کاهش یابد.
حملات رایج علیه JWT
هرچند JWT یک استاندارد امن محسوب میشود، اما پیادهسازی نادرست آن میتواند راه را برای حملات مختلف باز کند.
حمله XSS
در حملات Cross-Site Scripting، مهاجم موفق میشود کد JavaScript مخرب را در صفحه اجرا کند.
اگر JWT داخل LocalStorage یا SessionStorage ذخیره شده باشد، مهاجم میتواند آن را استخراج کرده و به سرور خود ارسال کند.
به همین دلیل جلوگیری از XSS اهمیت بسیار زیادی دارد.
حمله CSRF
اگر JWT داخل Cookie ذخیره شود و تنظیمات امنیتی مناسبی اعمال نشود، احتمال حملات Cross-Site Request Forgery وجود دارد.
استفاده از ویژگیهای SameSite و CSRF Token تا حد زیادی این مشکل را برطرف میکند.
سرقت Token
گاهی مهاجم نه از طریق ضعف نرمافزار، بلکه از طریق بدافزار، افزونههای مخرب مرورگر یا شبکههای ناامن موفق به سرقت Token میشود.
اگر عمر Access Token کوتاه باشد، میزان خسارت کاهش پیدا میکند.
Replay Attack
در این حمله، مهاجم درخواست معتبر کاربر را دوباره برای سرور ارسال میکند.
استفاده از Claimهایی مانند jti، زمان انقضای کوتاه و اعتبارسنجی مناسب میتواند احتمال موفقیت این حمله را کاهش دهد.
بهترین روشها (Best Practices) در استفاده از JWT
اگر قصد استفاده از JWT در پروژه خود را دارید، رعایت چند اصل مهم میتواند امنیت و کارایی سیستم را به شکل قابل توجهی افزایش دهد.
۱. همیشه از HTTPS استفاده کنید.
ارسال JWT روی ارتباط رمزنگارینشده میتواند باعث سرقت Token توسط افراد حاضر در مسیر ارتباط شود.
۲. عمر Access Token را کوتاه انتخاب کنید.
در بسیاری از پروژهها بازهای بین ۱۰ تا ۳۰ دقیقه انتخاب مناسبی است.
۳. از Refresh Token برای تمدید نشست کاربر استفاده کنید.
به جای افزایش بیش از حد اعتبار Access Token، از Refresh Token کمک بگیرید.
۴. اطلاعات حساس را داخل Payload قرار ندهید.
JWT برای نگهداری اطلاعات محرمانه طراحی نشده است.
۵. از Secret Key قوی استفاده کنید.
کلیدهای ساده مانند 123456 یا password امنیت سیستم را به شدت کاهش میدهند.
۶. الگوریتمهای امن را انتخاب کنید.
الگوریتمهایی مانند HS256، RS256 و ES256 انتخابهای مناسبی هستند.
۷. Tokenهای بلااستفاده را لغو کنید.
در صورت خروج کاربر، تغییر رمز عبور یا مشاهده فعالیت مشکوک، Refresh Token باید باطل شود.
۸. حداقل اطلاعات موردنیاز را داخل Token ذخیره کنید.
JWT هرچه کوچکتر باشد، سرعت ارسال و پردازش آن نیز بیشتر خواهد بود.
اشتباهات رایج هنگام استفاده از JWT
بسیاری از مشکلات امنیتی نه به خاطر JWT، بلکه به دلیل پیادهسازی اشتباه آن ایجاد میشوند.
رایجترین اشتباهات عبارتاند از:
- ذخیره رمز عبور داخل Payload
- تعیین اعتبار چندماهه یا چندساله برای Access Token
- استفاده از Secret Key ضعیف
- ارسال Token از طریق HTTP به جای HTTPS
-
عدم بررسی زمان انقضا (
exp) - اعتماد به اطلاعات Token بدون بررسی Signature
- قرار دادن اطلاعات غیرضروری داخل JWT
- عدم لغو Refresh Token پس از خروج کاربر
با پرهیز از این اشتباهات، میتوان از JWT به شکلی ایمن و کارآمد استفاده کرد.
چه زمانی استفاده از JWT پیشنهاد نمیشود؟
اگرچه JWT فناوری قدرتمندی است، اما همیشه بهترین انتخاب نیست.
برای مثال، اگر یک وبسایت کوچک با تعداد کاربران محدود دارید و تمام صفحات آن روی یک سرور اجرا میشوند، استفاده از Session Authentication ممکن است سادهتر و مناسبتر باشد.
همچنین در سیستمهایی که نیاز به لغو فوری دسترسی کاربران دارند و مدیریت Session اهمیت بالایی دارد، Session Authentication میتواند گزینه بهتری باشد.
در مقابل، اگر پروژه شما شامل API، اپلیکیشن موبایل، SPA یا چندین سرویس مستقل است، JWT معمولاً انتخاب مناسبتری خواهد بود.
سوالات متداول (FAQ)
JWT چیست؟
JWT یا JSON Web Token یک استاندارد برای انتقال امن اطلاعات بین کلاینت و سرور است که معمولاً برای احراز هویت و مدیریت دسترسی کاربران در APIها و برنامههای تحت وب استفاده میشود.
آیا اطلاعات داخل JWT رمزنگاری شده است؟
خیر. اطلاعات موجود در Payload فقط به صورت Base64Url Encode میشوند و رمزنگاری نیستند. بنابراین هر فردی که Token را در اختیار داشته باشد، میتواند محتوای آن را مشاهده کند. امنیت JWT به امضای دیجیتال (Signature) وابسته است، نه مخفی بودن اطلاعات.
تفاوت Authentication و Authorization چیست؟
Authentication به فرآیند احراز هویت کاربر و اطمینان از هویت او گفته میشود، در حالی که Authorization مشخص میکند کاربر پس از ورود، مجاز به انجام چه عملیات یا دسترسی به چه بخشهایی از سیستم است.
تفاوت Access Token و Refresh Token چیست؟
Access Token برای دسترسی به API استفاده میشود و معمولاً عمر کوتاهی دارد. Refresh Token عمر طولانیتری دارد و تنها برای دریافت Access Token جدید بدون نیاز به ورود مجدد کاربر استفاده میشود.
آیا JWT جایگزین Session Authentication است؟
خیر. JWT و Session Authentication هر دو روشهای معتبر احراز هویت هستند و انتخاب بین آنها به نوع پروژه، معماری سیستم و نیازهای امنیتی بستگی دارد.
آیا میتوان اطلاعات حساس را داخل JWT ذخیره کرد؟
خیر. اطلاعاتی مانند رمز عبور، اطلاعات بانکی، کلیدهای امنیتی یا سایر دادههای محرمانه نباید داخل JWT قرار بگیرند، زیرا Payload قابل مشاهده است.
بهترین محل ذخیره JWT کجاست؟
پاسخ به نیازهای پروژه بستگی دارد، اما در بسیاری از سناریوهای وب، استفاده از HttpOnly Cookie همراه با تنظیمات امنیتی مناسب، انتخاب امنتری نسبت به LocalStorage یا SessionStorage محسوب میشود.
اگر JWT منقضی شود چه اتفاقی میافتد؟
پس از پایان زمان اعتبار، سرور Token را نامعتبر تشخیص میدهد و درخواستهای ارسالشده با آن را رد میکند. در سیستمهایی که از Refresh Token استفاده میکنند، میتوان بدون ورود مجدد کاربر، Access Token جدید دریافت کرد.
آیا JWT فقط برای وبسایتها استفاده میشود؟
خیر. JWT علاوه بر وبسایتها، در اپلیکیشنهای موبایل، REST APIها، معماری Microservice، سرویسهای ابری و بسیاری از سامانههای مدرن نیز کاربرد گستردهای دارد.
آیا JWT امنیت بالایی دارد؟
در صورتی که از الگوریتم مناسب، کلیدهای امن، HTTPS و سایر اصول امنیتی استفاده شود، JWT یک روش قابل اعتماد و ایمن برای احراز هویت محسوب میشود. با این حال، امنیت نهایی به نحوه پیادهسازی آن بستگی دارد
جمعبندی
JWT یا JSON Web Token یکی از محبوبترین روشهای احراز هویت در برنامههای مدرن است که به دلیل Stateless بودن، سرعت بالا و سادگی در استفاده، جایگاه ویژهای در توسعه REST APIها، اپلیکیشنهای موبایل و معماریهای مبتنی بر سرویس پیدا کرده است.
در این مقاله با ساختار سهبخشی JWT شامل Header، Payload و Signature آشنا شدیم و دیدیم که امنیت آن بر پایه امضای دیجیتال بنا شده است. همچنین تفاوت Authentication و Authorization، نقش Access Token و Refresh Token، انواع Claimها، الگوریتمهای امضای رایج و مهمترین نکات امنیتی را بررسی کردیم.
با وجود مزایای فراوان، JWT راهحل همه مسائل نیست و انتخاب آن باید بر اساس نیازهای پروژه انجام شود. استفاده صحیح از HTTPS، تعیین اعتبار کوتاه برای Access Token، نگهداری امن Token و رعایت اصول امنیتی از مهمترین عواملی هستند که باعث میشوند JWT عملکردی ایمن و قابل اعتماد داشته باشد.
اگر این اصول به درستی رعایت شوند، JWT میتواند یک راهکار سریع، مقیاسپذیر و قابل اطمینان برای مدیریت هویت کاربران در انواع برنامههای تحت وب و موبایل باشد.
نظری ثبت نشده است.