JWT چیست و چگونه کار میکند؟
JSON Web Token یا JWT یک قالب استاندارد برای انتقال مجموعهای از «ادعاها» (Claims) بهصورت امضاشده است. توکن از سه بخش تشکیل میشود که با نقطه از هم جدا شده و هرکدام با Base64URL کدگذاری شدهاند:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9 ← header
.eyJzdWIiOiIxMDQyIiwicm9sZSI6InVzZXIifQ ← payload
.dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk ← signatureنکتهی اولی که باید روشن شود: Base64 رمزنگاری نیست. محتوای Payload برای هرکسی که توکن را دارد کاملاً خواناست. JWT محرمانگی نمیدهد، فقط یکپارچگی و اصالت میدهد — و آن هم فقط اگر راستیآزمایی امضا درست انجام شود. هرگز دادهی حساس را داخل Payload نگذارید.
هدر شامل فیلد alg است که الگوریتم امضا را اعلام میکند. و اینجا دقیقاً همانجایی است که بیشتر آسیبپذیریها متولد میشوند: اگر پیادهسازی سرور برای انتخاب روش راستیآزمایی به alg داخل خودِ توکن نگاه کند، مهاجم — که کنترل کامل روی توکن دارد — تصمیم میگیرد امضا چگونه بررسی شود.
حملات رایج علیه JWT
سند مرجع در این حوزه RFC 8725 با عنوان «JSON Web Token Best Current Practices» است. حملاتی که مستقیماً در آن یا در رویهی متعارف تست نفوذ مستندند:
alg: none— مهاجم الگوریتم راnoneمیگذارد و امضا را حذف میکند. RFC 8725 تصریح میکند برخی کتابخانهها توکن را «بدون بررسی هیچ امضایی» معتبر میشمردند. گونههای حساس به حروف مثلNoneوnOnEبرای دور زدن فهرستهای سیاه ناقص هم آزموده میشوند.- سردرگمی کلید / جایگزینی الگوریتم (RS256 → HS256) — مهاجم
algرا از RS256 به HS256 تغییر میدهد و توکن را با کلید عمومی سرور بهعنوان کلید مشترک HMAC امضا میکند. اگر کتابخانه بر پایهیalgتوکن تصمیم بگیرد و «کلید» را بهصورت عمومی پاس بدهد، امضا با همان کلید عمومی — که مهاجم هم دارد — تأیید میشود. RFC 8725 دقیقاً همین سناریو را توصیف میکند. - کلید متقارن ضعیف — رمزهای HMAC قابل شکستن با دیکشنری. مقادیر پیشفرض فریمورکها و رشتههای کوتاه، با
hashcat -m 16500در زمان کوتاهی شکسته میشوند. - تزریق هدرهای
jkuوx5u— این هدرها آدرس مجموعهکلید را مشخص میکنند. اگر سرور آدرس را از توکن بپذیرد، مهاجم آن را به میزبان خودش اشاره میدهد. این حمله با SSRF زنجیر میشود. - تزریق هدر
jwk— جاسازی کلید عمومی مهاجم مستقیماً در هدر توکن و اعتماد سرور به آن. - تزریق
kid— این فیلد شناسهی کلید است و اغلب برای جستوجو در فایلسیستم یا پایگاهداده استفاده میشود؛ در نتیجه هم پیمایش مسیر و هم تزریق SQL از این نقطه گزارش شدهاند. - نبود اعتبارسنجی
aud،iss،expوnbf— توکن معتبرِ منقضیشده، یا توکنی که برای سرویس دیگری صادر شده و اینجا هم پذیرفته میشود. - جایگزینی توکن بین زمینهها — توکنی که برای سرویس A صادر شده، در سرویس B معتبر شمرده میشود. RFC 8725 برای همین، استفاده از تایپ صریح (
typ) را توصیه میکند.
قاعدهی اصلی: برنامه الگوریتم را تعیین میکند، نه توکن
اگر قرار باشد از این صفحه فقط یک جمله را به تیم توسعه منتقل کنید، همین است. توصیههای RFC 8725 را میتوان چنین خلاصه کرد:
- کتابخانه باید الگوریتمها را به یک فهرست سفید محدود کند و راستیآزمایی کند که الگوریتم اعلامشده در هدر با عملیات رمزنگاریای که واقعاً انجام میشود مطابقت دارد.
- فقط الگوریتمهای بهروز مجاز باشند.
- هر شکست در هر عملیات رمزنگاری باید به رد کل توکن منجر شود.
- هرگز از رمز عبور قابل حفظ توسط انسان بهعنوان کلید MAC استفاده نشود؛ آنتروپی کافی الزامی است.
- ادعاهای
audوissاعتبارسنجی شوند و تعلق کلید به صادرکنندهی ادعاشده تأیید شود. OWASP هم در A07:2025 همین دو ادعا را صراحتاً نام میبرد. - از تایپ صریح برای جلوگیری از سردرگمی توکن بین زمینههای مختلف استفاده شود.
در عمل یعنی: بهجای verify(token, key) که الگوریتم را از توکن میخواند، باید verify(token, key, algorithms=["ES256"]) نوشته شود.
آیا JWT از نشست سمت سرور امنتر است؟
«JWT از Session امنتر است.» این یک مصالحهی متفاوت است، نه یک ارتقا. JWT برای مجوزدهی توزیعشده و بدونوضعیت طراحی شده و در همان جا ارزش دارد. اما ابطال آن دشوار است (توکن تا لحظهی انقضا معتبر میماند، حتی پس از خروج کاربر یا تغییر نقش)، اغلب در localStorage نگهداری میشود که هر XSS آن را میخواند، و کل سطح حملهی راستیآزمایی امضا را اضافه میکند. برای یک برنامهی یکپارچهی تکسروری، نشست کدر (Opaque) سمت سرور معمولاً انتخاب امنتری است.
مقایسهی صادقانه:
| معیار | نشست سمت سرور | JWT |
|---|---|---|
| ابطال فوری | ساده — رکورد را حذف کنید | دشوار؛ نیاز به فهرست سیاه که خودِ بدونوضعیت بودن را نقض میکند |
| مقیاسپذیری افقی | نیاز به ذخیرهساز مشترک | بدون نیاز به ذخیرهساز مشترک |
| سطح حملهی رمزنگاری | ناچیز | الگوریتم، کلید، هدرها، ادعاها |
| محل نگهداری امن | کوکی HttpOnly | کوکی HttpOnly — نه localStorage |
توجه کنید که نگهداری توکن در کوکی، مسئلهی CSRF را برمیگرداند و باید با توکن همزمانساز یا هدر سفارشی پوشش داده شود. هیچ گزینهای رایگان نیست؛ انتخاب باید آگاهانه باشد.
چگونه در تست نفوذ کشف میشود
- یافتن توکن: هدر
Authorization: Bearer، کوکیها، و بهویژهlocalStorageوsessionStorageدر پنل Application مرورگر. حضور توکن درlocalStorageخودش یک یافته است. - رمزگشایی و بازبینی ادعاها: آیا
expوجود دارد و کوتاه است؟ آیاaudوissهستند؟ آیا ادعاهای نقش (role،scope،tenant) در توکناند و سرور به آنها اعتماد میکند؟ - آزمون امضا: امضا را حذف کنید؛ یک بایت از امضا را تغییر دهید؛
algرا رویnoneبگذارید؛ RS256 را به HS256 تبدیل کنید و با کلید عمومی سرور امضا کنید (کلید عمومی معمولاً در/.well-known/jwks.jsonدر دسترس است). - آزمون هدرها:
jku،x5u،jwkوkidرا دستکاری کنید و پاسخ سرور و ترافیک خروجی را رصد کنید. - آزمون کلید ضعیف: برای توکنهای HS256 با
hashcat -m 16500و یک فهرست رمز متعارف، شکستن کلید را بیازمایید. - آزمون چرخهی حیات: پس از خروج کاربر، همان توکن را دوباره بفرستید. اگر هنوز کار میکند — که در پیادهسازیهای بدونوضعیت معمول است — این را در گزارش با اثر واقعیاش بنویسید.
ابزار متعارف: افزونهی JWT Editor در Burp Suite، ابزار jwt_tool و hashcat. توجه کنید که این آزمونها بخش استانداردی از تست نفوذ API هستند و اسکنرهای عمومی معمولاً فقط حالت alg: none را پوشش میدهند.
نگاشت به OWASP و CWE
- A07:2025 — Authentication Failures: خانهی اصلی نقصهای JWT. OWASP در همین دسته صراحتاً میگوید برای JWT باید ادعاهای
audوissاعتبارسنجی شوند. - A01:2025 — Broken Access Control: وقتی دستکاری ادعای نقش داخل توکن به ارتقای سطح دسترسی منجر شود، یافته اینجا ردهبندی میشود. OWASP در همین دسته توصیه میکند عمر JWT کوتاه نگه داشته شود.
- CWE-287 (احراز هویت نادرست) و CWE-347 (راستیآزمایی نادرست امضای رمزنگاری) نزدیکترین شناسههای CWE هستند؛ برای کلید ثابت جاسازیشده CWE-798.
پرسشهای متداول
آیا JWT از نشست سمت سرور امنتر است؟
خیر، یک مصالحهی متفاوت است. JWT بدونوضعیت بودن و مقیاسپذیری در معماری توزیعشده را میدهد، اما ابطال فوری را سخت میکند و سطح حملهی راستیآزمایی امضا را اضافه میکند. برای یک برنامهی یکپارچه، نشست کدر سمت سرور معمولاً سادهتر و امنتر است.
آیا محتوای JWT رمزنگاری شده است؟
در حالت متعارف (JWS) خیر. سه بخش توکن فقط با Base64URL کدگذاری شدهاند و هرکس توکن را داشته باشد میتواند Payload را بخواند. امضا فقط جلوی تغییر محتوا را میگیرد، نه خواندن آن. برای محرمانگی باید از JWE استفاده کرد — یا سادهتر، دادهی حساس را اصلاً داخل توکن نگذارید.
حملهی سردرگمی کلید در JWT چیست؟
مهاجم الگوریتم را از یک الگوریتم نامتقارن مثل RS256 به یک الگوریتم متقارن مثل HS256 تغییر میدهد و توکن را با کلید عمومی سرور بهعنوان کلید مشترک HMAC امضا میکند. کلید عمومی معمولاً آزادانه در دسترس است. اگر کتابخانه الگوریتم را از خود توکن بخواند، امضا معتبر شمرده میشود. راهحل، تثبیت فهرست الگوریتمهای مجاز در سمت سرور است.
JWT را کجا ذخیره کنیم؟
در کوکی با صفات HttpOnly، Secure و SameSite. نگهداری در localStorage رایج است اما توکن را برای هر XSS خواندنی میکند و هیچ سازوکار مرورگری از آن محافظت نمیکند. اگر کوکی را انتخاب کردید، دفاع CSRF را هم اضافه کنید.