پرش به محتوای اصلی
آسیب‌پذیری‌های سایت

امنیت JWT چیست؟ اشتباهات رایج در توکن‌های احراز هویت و روش‌های محافظت از آن‌ها

امنیت JWT به نحوه صدور، امضا، نگهداری، اعتبارسنجی و باطل‌کردن JSON Web Tokenهای مورد استفاده در احراز هویت و APIها مربوط می‌شود. ضعف‌هایی مانند alg=none، Algorithm Confusion، Secret ضعیف، Token طولانی‌عمر، اعتبارسنجی نکردن iss و aud و ذخیره JWT در محل ناامن می‌توانند زمینه جعل یا سرقت حساب را ایجاد کنند. استفاده از Algorithm Allowlist، کلیدهای قوی، Access Token کوتاه‌عمر، Refresh Token Rotation، HTTPS، Revocation و Storage امن از مهم‌ترین اصول امنیت JWT هستند.

تیم امنیت رخنه‌کاو ۴۱ دقیقه مطالعه انتشار:

پاسخ کوتاه: امنیت JWT یعنی تولید، امضا، اعتبارسنجی، نگهداری و باطل‌کردن JSON Web Tokenها به شکلی که مهاجم نتواند توکن جعلی بسازد، اطلاعات آن را دستکاری کند، توکن دزدیده‌شده را دوباره استفاده کند یا از ضعف الگوریتم و کلید امضا سوءاستفاده کند. مهم‌ترین اقدامات دفاعی شامل محدودکردن الگوریتم‌های مجاز، استفاده از کلیدهای قوی، اعتبارسنجی exp، iss و aud، کوتاه‌کردن عمر Access Token، محافظت از Refresh Token، جلوگیری از ذخیره ناامن توکن در مرورگر و داشتن مکانیزم Revocation است.

JWT یا JSON Web Token در سال‌های اخیر به یکی از رایج‌ترین فناوری‌ها برای انتقال اطلاعات احراز هویت و مجوز دسترسی میان سرویس‌ها تبدیل شده است. بسیاری از APIها، برنامه‌های موبایل، معماری‌های Microservice، سامانه‌های Single Sign-On و پیاده‌سازی‌های OAuth و OpenID Connect از JWT استفاده می‌کنند.

سادگی ظاهری JWT می‌تواند گمراه‌کننده باشد.

یک رشته متنی شامل سه بخش که با نقطه از یکدیگر جدا شده‌اند، در نگاه اول پیچیدگی زیادی ندارد. Developer توکن را ایجاد می‌کند، Client آن را همراه درخواست ارسال می‌کند و Server Signature را بررسی می‌کند.

اما امنیت واقعی JWT فقط به «وجود Signature» بستگی ندارد.

انتخاب اشتباه Algorithm، قبول‌کردن alg=none، استفاده از Secret ضعیف، اعتبارسنجی نکردن aud و iss، نگهداری Access Token در محل ناامن، نداشتن Expiration مناسب یا طراحی نامناسب Refresh Token می‌تواند یک سیستم ظاهراً مدرن را به یک معماری احراز هویت آسیب‌پذیر تبدیل کند.

IETF به همین دلیل علاوه بر استاندارد اصلی JWT یعنی RFC 7519، سند مستقل RFC 8725 – JSON Web Token Best Current Practices را منتشر کرده است. این سند روی تهدیدهایی مانند Weak Signature، Algorithm Confusion، کلیدهای HMAC ضعیف، Token Type Confusion و اعتبارسنجی نادرست Issuer و Audience تمرکز دارد.

نکته مهم دیگر این است که JWT الزاماً بهترین انتخاب برای هر سیستم Session نیست. OWASP صراحتاً توصیه می‌کند قبل از انتخاب JWT برای Sessionهای به‌اصطلاح Stateless بررسی شود که آیا واقعاً به آن نیاز داریم یا یک Session معمولی Server-Side گزینه ساده‌تر و قابل‌کنترل‌تری است؛ زیرا به محض اینکه به Logout، Revocation و مدیریت Session نیاز پیدا کنیم، بخشی از مزیت Stateless بودن از بین می‌رود.

در این مقاله از رخنه‌کاو بررسی می‌کنیم JWT چیست، ساختار آن چگونه کار می‌کند، Signature دقیقاً از چه چیزی محافظت می‌کند، مهم‌ترین اشتباهات امنیت JWT کدام‌اند و برای جلوگیری از جعل، سرقت و Replay توکن‌های احراز هویت چه معماری دفاعی مناسبی باید پیاده‌سازی شود.

JWT چیست؟

JWT مخفف:

JSON Web Token

است.

RFC 7519 آن را قالبی فشرده و URL-Safe برای انتقال مجموعه‌ای از Claimها میان طرفین تعریف می‌کند. Claim در اینجا به معنی یک ادعا یا اطلاعات درباره Subject، Issuer، زمان اعتبار یا سایر ویژگی‌های مرتبط با Token است.

برای مثال یک JWT ممکن است به‌صورت مفهومی اعلام کند:

کاربر با شناسه 152 وارد سیستم شده است.

Issuer این Token سرویس Authentication شرکت است.

Token برای API فروشگاه صادر شده است.

Token تا ساعت مشخصی اعتبار دارد.

Role فعلی کاربر editor است.

این اطلاعات می‌توانند در Payload قرار گیرند و Integrity آن‌ها با Signature محافظت شود. ساختار JWT چگونه است؟

ساختار JWT چگونه است؟

رایج‌ترین نوع JWT که در سیستم‌های احراز هویت مشاهده می‌شود یک JWT امضاشده یا Signed JWT است.

ساختار معمول آن:

Header.Payload.Signature

است.

هر بخش با نقطه از دیگری جدا می‌شود.

OWASP ساختار Signed JWT را به‌صورت مفهومی چنین تعریف می‌کند:

base64url(header).base64url(claims).base64url(signature)

Signature روی Header و Payload محاسبه می‌شود تا تغییر غیرمجاز این بخش‌ها قابل تشخیص باشد.

Header چیست؟

Header اطلاعات فنی Token را نگهداری می‌کند.

برای مثال:

alg

نوع الگوریتم Signature را مشخص می‌کند.

و:

typ

می‌تواند نوع Token را مشخص کند.

نمونه مفهومی:

{
  "alg": "ES256",
  "typ": "JWT"
}

ممکن است Headerهای دیگری مانند:

kid

jwk

jku

x5u

نیز وجود داشته باشند که به Key Selection مربوط می‌شوند و در صورت استفاده نادرست می‌توانند Security Risk ایجاد کنند.

Payload چیست؟

Payload شامل Claimهاست.

برای مثال:

{
  "sub": "user-152",
  "iss": "https://auth.example.com",
  "aud": "https://api.example.com",
  "exp": 1788450000,
  "iat": 1788446400
}

این Claimها مفهوم‌های مشخصی دارند که بعداً بررسی می‌کنیم.

Signature چیست؟

Signature به Receiver کمک می‌کند بررسی کند Header و Payload بعد از صدور Token تغییر نکرده‌اند و Token توسط کسی که Key معتبر را در اختیار دارد تولید شده است.

بسته به Algorithm، Signature ممکن است با:

Shared Secret

یا:

Private Key

ساخته شود.

Base64URL رمزنگاری نیست

یکی از مهم‌ترین سوءبرداشت‌ها درباره امنیت JWT این است:

Payload معمول JWT رمزگذاری نشده است.

Header و Payload اغلب فقط Base64URL Encode شده‌اند.

هر کسی که Token را داشته باشد می‌تواند این بخش‌ها را Decode کند.

بنابراین اطلاعاتی مثل:

Password

API Secret

Private Key

شماره کارت

Credential

و سایر اطلاعات محرمانه نباید صرفاً به این دلیل که داخل JWT هستند، «مخفی» فرض شوند.

Signature از Integrity و Authenticity محافظت می‌کند، نه الزاماً Confidentiality.

RFC 8725 نیز JWTهای Signed و Encrypted را از یکدیگر تفکیک می‌کند. اگر Confidentiality موردنیاز باشد باید از مکانیزم مناسب مانند JWE یا معماری دیگری استفاده شود.

JWS و JWE چه تفاوتی دارند؟

JSON Web Signature یا JWS برای Signature استفاده می‌شود.

بیشتر JWTهای رایج Authentication در واقع JWTهایی هستند که به شکل JWS امضا شده‌اند.

JWE یا JSON Web Encryption برای Encryption محتوا طراحی شده است.

در JWT معمولی Signed:

Client می‌تواند Claimها را ببیند.

اما نباید بتواند بدون شکستن Signature آن‌ها را تغییر دهد.

در JWE:

هدف علاوه بر Integrity، ایجاد Confidentiality برای محتواست.

بنابراین نباید تصور کرد هر رشته JWT خودبه‌خود Encrypted است.

مهم‌ترین Claimهای امنیتی JWT

RFC 7519 چند Claim استاندارد مهم تعریف می‌کند.

iss یا Issuer

iss

مشخص می‌کند چه Entity یا Authorization Server توکن را صادر کرده است.

مثلاً:

https://auth.example.com

Receiver باید بداند Issuer مورد اعتماد چه کسی است.

sub یا Subject

sub

هویت Subject توکن را مشخص می‌کند.

در بسیاری از سیستم‌ها این مقدار User ID است.

مثلاً:

user-735

aud یا Audience

aud

مشخص می‌کند Token برای کدام سرویس یا Application صادر شده است.

مثلاً:

https://billing-api.example.com

این Claim نقش مهمی در جلوگیری از Token Confusion دارد.

exp یا Expiration Time

exp

زمان پایان اعتبار JWT را مشخص می‌کند.

بعد از این زمان Token نباید معتبر شناخته شود.

nbf یا Not Before

nbf

اعلام می‌کند Token قبل از چه زمانی نباید پذیرفته شود.

iat یا Issued At

iat

زمان صدور Token را مشخص می‌کند.

jti یا JWT ID

jti

یک Identifier یکتا برای Token است.

این Claim می‌تواند برای Audit، Tracking و بعضی معماری‌های Revocation یا Replay Detection مفید باشد. RFC 7519 نیز اشاره می‌کند jti می‌تواند در جلوگیری از Replay کاربرد داشته باشد. امنیت JWT از کجا شروع می‌شود؟

امنیت JWT از کجا شروع می‌شود؟

امنیت JWT از لحظه صدور Token آغاز نمی‌شود.

زنجیره واقعی شامل موارد زیر است:

Authentication کاربر ↓ Token Issuance ↓ Signing ↓ Transmission ↓ Storage ↓ Validation ↓ Authorization ↓ Expiration ↓ Refresh ↓ Revocation

اگر هر بخش این زنجیره اشتباه طراحی شود، Signature صحیح به‌تنهایی سیستم را امن نمی‌کند.

اشتباه اول: اعتماد به الگوریتم اعلام‌شده داخل Token

یکی از شناخته‌شده‌ترین خطاهای JWT زمانی رخ می‌دهد که Validator بیش از حد به مقدار:

alg

داخل Token اعتماد کند.

فراموش نکنید:

Header JWT بخشی از داده‌ای است که Client ارائه می‌کند.

بنابراین Application نباید بگوید:

«هر الگوریتمی Token درخواست کرد با همان اعتبارسنجی می‌کنم.»

الگوریتم‌های مجاز باید سمت Server مشخص باشند.

مثلاً اگر سیستم فقط از ES256 استفاده می‌کند:

Validator باید فقط ES256 را بپذیرد.

RFC 8725 صراحتاً توصیه می‌کند Library اجازه انتخاب هر Algorithm دلخواه توسط Token را ندهد و Caller مجموعه Algorithmهای مجاز را Explicitly مشخص کند.

قاعده دفاعی:

Algorithm Policy باید توسط Server تعیین شود، نه Token دریافتی.

اشتباه دوم: قبول کردن alg=none

استاندارد JWT امکان Token بدون Signature را برای Use Caseهای خاص تعریف کرده است.

در این حالت Header ممکن است شامل:

"alg":"none"

باشد.

وجود این قابلیت در استاندارد به معنی مناسب بودن آن برای Authentication عمومی نیست.

مشکل تاریخی زمانی ایجاد شد که بعضی Libraryها JWTهای none را در Contextهایی که Signature لازم بود معتبر می‌دانستند.

در چنین شرایطی مهاجم می‌توانست Claimهایی مانند User ID یا Role را تغییر دهد و Token بدون Signature بسازد.

RFC 8725 این مشکل را به‌عنوان یکی از نمونه‌های ضعف Signature Validation مطرح می‌کند و OWASP نیز توصیه می‌کند JWT Parser در سیستم احراز هویت alg=none را قبول نکند.

در سیستم Authentication:

Unsecured JWT نباید به‌صورت تصادفی پذیرفته شود. Algorithm Confusion

اشتباه سوم: Algorithm Confusion

Algorithm Confusion یا Key Type Confusion یکی از مشکلات مهم JWT Validation است.

JWT می‌تواند از الگوریتم‌های Symmetric مانند:

HS256

یا Asymmetric مانند:

ES256

PS256

RS256

استفاده کند.

در HMAC:

هم Issuer و هم Validator یک Shared Secret دارند.

اما در Public-Key Signature:

Issuer با Private Key امضا می‌کند و Validator با Public Key Signature را بررسی می‌کند.

در بعضی پیاده‌سازی‌های آسیب‌پذیر، مهاجم می‌توانست Tokenی که انتظار می‌رفت با RSA یا EC بررسی شود به HMAC تبدیل کند و Validator به اشتباه Public Key را به‌عنوان Secret HMAC استفاده کند.

RFC 8725 این سناریو را به‌طور مشخص شرح می‌دهد و OWASP نیز توصیه می‌کند Algorithmهای MAC و Public-Key بدون کنترل سخت‌گیرانه با یکدیگر Mix نشوند.

راهکار:

  • Algorithmهای مجاز Explicit باشند.
  • نوع Key با Algorithm سازگار باشد.
  • Library به‌روز و معتبر باشد.
  • Token اجازه تغییر Security Policy را نداشته باشد.

اشتباه چهارم: استفاده از Secret ضعیف در HS256

HS256 الگوریتم HMAC بر پایه SHA-256 است.

امنیت آن تا حد زیادی به Secret وابسته است.

Secretهایی مانند:

secret

myjwtsecret

company2026

password123

انتخاب‌های خطرناکی هستند.

چرا؟

چون مهاجمی که یک JWT معتبر در اختیار دارد ممکن است بتواند روی Secret ضعیف Offline Guessing انجام دهد.

RFC 8725 هشدار می‌دهد Symmetric Keyهایی که Entropy کافی ندارند در برابر Dictionary و Brute-Force Attack آسیب‌پذیرند. RFC 7518 نیز برای HS256 Key با اندازه حداقل برابر خروجی Hash یعنی 256 بیت را الزام می‌کند.

بنابراین Secret باید:

  • Random باشد.
  • Cryptographically Secure تولید شود.
  • به‌اندازه کافی طولانی باشد.
  • داخل Source Code نوشته نشود.
  • بین Environmentها مشترک نباشد.
  • قابلیت Rotation داشته باشد.

OWASP نیز توصیه می‌کند Password یا Passphrase انسانی به‌عنوان MAC Secret استفاده نشود.

اشتباه پنجم: Hardcode کردن JWT Secret در Source Code

یکی از اشتباهات رایج:

JWT_SECRET=my-secret

داخل Repository پروژه است.

اگر Secret داخل Git قرار بگیرد ممکن است در:

Repository History

Fork

CI Log

Backup

Developer Laptop

Container Image

باقی بماند.

حتی اگر بعداً Commit پاک شود، Key باید Compromised فرض شود و Rotate شود.

راهکار مناسب استفاده از:

Secret Manager

Environment Configuration امن

KMS

Vault

یا مکانیزم مدیریت Secret سازمان است.

اشتباه ششم: استفاده از یک Key برای همه چیز

یک Key نباید بی‌دلیل برای چند کاربرد امنیتی مختلف استفاده شود.

مثلاً:

JWT Signing

Data Encryption

Password Reset

Webhook Signature

همگی با یک Secret.

این کار Blast Radius نشت Key را افزایش می‌دهد.

OWASP نیز توصیه می‌کند Signing Key یا MAC Secret برای Purposeهای دیگر Reuse نشود.

همچنین Secret HMAC نباید بدون تحلیل بین Issuerها یا Audienceهای مختلف مشترک باشد؛ زیرا Entityای که Secret را برای Verify کردن در اختیار دارد، در HMAC عملاً توانایی ساخت Signature نیز دارد.

HMAC یا Public-Key Signature؛ کدام بهتر است؟

پاسخ وابسته به Architecture است.

HMAC

مانند:

HS256

مزیت:

ساده و سریع.

اما Issuer و Validator باید Secret مشترک داشته باشند.

یعنی هر Service دارای Secret می‌تواند Token معتبر تولید کند.

Public-Key Signature

مانند:

ES256

PS256

Issuer Private Key را نگه می‌دارد.

Validator فقط Public Key را دارد.

بنابراین Resource Server لازم نیست Secretی داشته باشد که بتوان با آن JWT جعل کرد.

این مدل برای سیستم‌های Distributed و چند API معمولاً Security Boundary بهتری ایجاد می‌کند.

OWASP نیز یکی از مزایای Digital Signature را این می‌داند که Audience فقط به Public Key نیاز دارد و نشت Public Key امکان امضای Token را ایجاد نمی‌کند.

اشتباه هفتم: نداشتن Key Rotation

حتی Key قوی نباید لزوماً برای همیشه استفاده شود.

ممکن است:

Developer دسترسی خود را از دست بدهد.

Secret در Backup قدیمی باشد.

Infrastructure Compromise شود.

سیاست Cryptographic تغییر کند.

برای همین Key Rotation باید بخشی از Architecture باشد.

در معماری Asymmetric معمولاً:

kid

یا Key ID

به Validator کمک می‌کند مشخص کند Token با کدام Key امضا شده است.

در Rotation می‌توان برای مدتی چند Public Key معتبر داشت تا Tokenهای قدیمی تا پایان عمرشان Validate شوند، سپس Key قدیمی حذف شود.

اشتباه هشتم: اعتماد مستقیم به kid، jku یا jwk

Header JWT می‌تواند Parameterهایی برای انتخاب Verification Key داشته باشد.

موارد مهم:

kid

jwk

jku

x5u

x5c

اگر Application این داده‌ها را مستقیماً Trust کند، مهاجم ممکن است Verification Process را تحت تأثیر قرار دهد.

OWASP هشدار می‌دهد Verification Key نباید صرفاً از Header توکن دریافتی گرفته و مورد اعتماد قرار گیرد. Trust باید به Issuer یا Trust Anchor از پیش شناخته‌شده متصل باشد.

برای مثال jku یک URL مربوط به JWK Set است.

Server نباید بدون محدودیت هر URLای را که Token معرفی می‌کند Fetch و Trust کند.

این کار علاوه بر Key Trust Risk می‌تواند SSRF Risk نیز ایجاد کند.

راهکار:

  • Trusted Issuer از قبل مشخص باشد.
  • JWKS URI از Metadata معتبر گرفته شود.
  • Domainهای قابل اعتماد محدود باشند.
  • kid فقط در مجموعه Keyهای Trusted جست‌وجو شود.
  • Input مربوط به kid Sanitization داشته باشد.

اشتباه نهم: فقط Decode کردن JWT بدون Verify Signature

JWT Decode کردن بسیار ساده است.

ابزارها و Libraryهای مختلف می‌توانند Payload را بدون Key نمایش دهند.

این باعث یک اشتباه خطرناک می‌شود:

Developer Token را Decode می‌کند و Claimها را استفاده می‌کند، بدون اینکه Signature واقعاً Verify شده باشد.

مثلاً:

Payload می‌گوید:

role = admin

اما تا زمانی که Signature Verify نشده باشد، این مقدار Trustworthy نیست.

قاعده:

Decode ≠ Validate

JWT باید ابتدا Cryptographically Validate شود و سپس Claimهای امنیتی آن بررسی شوند.

اشتباه دهم: بررسی Signature ولی نادیده گرفتن exp

حتی Token با Signature کاملاً معتبر ممکن است Expire شده باشد.

Signature فقط ثابت می‌کند Token توسط Key معتبر صادر شده و تغییر نکرده است.

نمی‌گوید:

Token هنوز باید پذیرفته شود.

exp

برای همین وجود دارد.

Server باید Expiration را Validate کند.

اگر Access Token بدون Expiration باشد یا مدت بسیار طولانی داشته باشد، در صورت سرقت پنجره سوءاستفاده افزایش پیدا می‌کند.

برای APIهای حساس بهتر است Access Token کوتاه‌عمر باشد.

Access Token چقدر عمر داشته باشد؟

یک عدد جهانی برای همه سیستم‌ها وجود ندارد.

Risk به مواردی مانند:

نوع Application

ارزش Data

امکان Refresh

Device

Scope

Audience

Reauthentication

وابسته است.

اما اصل کلی:

Access Token کوتاه‌عمر + Refresh Mechanism امن

معمولاً بهتر از Access Token بسیار طولانی است.

RFC 9700 نیز Short-Lived Access Token و محدودکردن Scope را از روش‌های کاهش اثر Token Leakage می‌داند.

اشتباه یازدهم: اعتبارسنجی نکردن nbf

اگر Token دارای:

nbf

است، نباید قبل از زمان تعیین‌شده معتبر باشد.

RFC 7519 می‌گوید پردازش Token باید بعد یا برابر زمان Not Before باشد.

می‌توان مقدار کمی Clock Skew منطقی در نظر گرفت؛ اما حذف کامل Validation اشتباه است.

اشتباه دوازدهم: اعتبارسنجی نکردن Issuer

فرض کنید سازمان دو Identity Provider دارد:

Trusted Auth

و

Test Auth

اگر API فقط Signature را Verify کند اما:

iss

را Validate نکند، ممکن است Token صادرشده در Context اشتباه پذیرفته شود.

RFC 8725 تأکید می‌کند وقتی iss وجود دارد، Application باید Issuer را بررسی و Key را به همان Issuer معتبر متصل کند.

بنابراین:

Valid Signature

به‌تنهایی کافی نیست.

باید مشخص باشد:

چه کسی Token را صادر کرده؟

اشتباه سیزدهم: نادیده گرفتن Audience

این یکی از مهم‌ترین خطاهای معماری Multi-Service است.

فرض کنید:

Token A

برای:

Billing API

صادر شده است.

اما مهاجم همان Token را برای:

Admin API

ارسال می‌کند.

اگر Admin API صرفاً Signature را Validate کند و aud را بررسی نکند، ممکن است Token اشتباه پذیرفته شود.

RFC 8725 صراحتاً می‌گوید اگر Issuer برای چند Application Token صادر می‌کند، Audience باید مشخص و توسط Receiver اعتبارسنجی شود.

قاعده:

Token صادرشده برای Service A نباید خودکار در Service B معتبر باشد.

اشتباه چهاردهم: Token Type Confusion

در اکوسیستم OAuth و OpenID Connect انواع Tokenهای مختلف وجود دارند.

مثلاً:

ID Token

Access Token

Refresh Token

این Tokenها وظایف متفاوت دارند.

ID Token درباره Authentication و Identity است.

Access Token برای Access به Resource Server استفاده می‌شود.

یکی از مشکلات امنیتی زمانی ایجاد می‌شود که Application Token مخصوص یک Context را در Context دیگری قبول کند.

RFC 8725 توصیه می‌کند Ruleهای Validation برای انواع مختلف JWT mutually exclusive باشند و از Explicit Typing و Audience مناسب برای کاهش Cross-JWT Confusion استفاده شود.

بنابراین نباید:

«هر JWT با Signature معتبر»

را Token مناسب همه Endpointها فرض کرد.

اشتباه پانزدهم: قرار دادن اطلاعات محرمانه در Payload

Payload JWT معمولاً قابل Decode است.

بنابراین قرار دادن اطلاعات زیر در Signed JWT معمولی اشتباه است:

Password

Secret Key

Recovery Code

شماره کامل کارت

اطلاعات محرمانه پزشکی

Credentialهای داخلی

Tokenهای دیگر

حتی اطلاعات شخصی غیرضروری نیز بهتر است طبق اصل Data Minimization حذف شوند.

JWT فقط باید Claimهایی را داشته باشد که Consumer واقعاً نیاز دارد.

آیا Email و Username را می‌توان داخل JWT گذاشت؟

از نظر فنی بله.

اما سؤال بهتر این است:

آیا Consumer واقعاً به آن نیاز دارد؟

اگر فقط:

sub

برای شناسایی User کافی است، حمل Email، Full Name و سایر اطلاعات در تمام Requestها ممکن است غیرضروری باشد.

مزایای حداقل‌سازی Claim:

کاهش Information Exposure

کاهش Token Size

کاهش داده قدیمی

کاهش Privacy Risk

اشتباه شانزدهم: گذاشتن Role طولانی‌عمر داخل JWT

فرض کنید Token حاوی:

role=admin

است.

سه ساعت بعد Administrator Role کاربر حذف می‌شود.

اگر JWT همچنان دو روز اعتبار داشته باشد و سیستم Authorization فقط به Claim داخل Token اعتماد کند، کاربر ممکن است تا پایان Token همچنان Access قبلی را داشته باشد.

این یکی از Trade-offهای Token Stateless است.

برای مجوزهای بسیار حساس می‌توان از:

Access Token کوتاه‌عمر

Online Authorization Check

Token Introspection

Session Version

یا Reauthentication

استفاده کرد.

اصل مهم:

Authorization Data نباید بیشتر از مدت قابل قبول Business stale بماند.

JWT و Authentication با Authorization یکی نیستند

یکی از خطاهای مهم:

Token معتبر است ↓ پس کاربر به همه چیز دسترسی دارد

نیست.

JWT ممکن است Identity را ثابت کند.

اما هر Endpoint باید Authorization مناسب خودش را بررسی کند.

مثلاً کاربر:

Authenticated

است.

اما آیا:

edit_user

یا:

delete_order

یا:

manage_settings

را مجاز است؟

Authentication پاسخ می‌دهد:

«این فرد چه کسی است؟»

Authorization پاسخ می‌دهد:

«اجازه انجام چه کاری را دارد؟»

Security JWT نباید جای Access Control را بگیرد.

اشتباه هفدهم: ذخیره JWT در localStorage

این یکی از بحث‌برانگیزترین موضوعات امنیت Frontend است.

localStorage

برای JavaScript همان Origin قابل دسترس است.

اگر سایت XSS داشته باشد، Script مهاجم می‌تواند Token موجود در LocalStorage را بخواند.

OWASP Session Management Cheat Sheet در نسخه فعلی صراحتاً هشدار می‌دهد Authentication Token، Session ID، JWT و Refresh Token در localStorage یا sessionStorage ذخیره نشوند؛ زیرا JavaScript اجراشده در Origin می‌تواند آن‌ها را افشا کند.

بنابراین برای Browser-Based Session اغلب باید الگوهایی مانند:

HttpOnly Cookie

یا:

Backend-for-Frontend

بررسی شوند. Secure، HttpOnly و محل نگهداری JWT در مرورگر

برای بسیاری از Browser-Based Authenticationها گزینه بسیار خوبی است، اما Trade-off دارد.

مزیت:

JavaScript نمی‌تواند Token را مستقیماً بخواند.

در نتیجه سرقت Token در بسیاری از XSSها دشوارتر می‌شود.

اما Browser Cookie را خودکار همراه Request می‌فرستد.

پس CSRF باید مدیریت شود.

Cookie حساس معمولاً باید بر اساس معماری دارای:

HttpOnly

Secure

و:

SameSite

مناسب باشد.

NIST نیز برای Session Cookie استفاده از HTTPS، HttpOnly و SameSite=Lax یا Strict را توصیه می‌کند.

دو الگوی رایج وجود دارد.

Authorization Header

Client Token را مثلاً با:

Authorization: Bearer <token>

ارسال می‌کند.

مزیت:

Browser خودکار Token را Cross-Site ارسال نمی‌کند.

اما اگر Token در JavaScript Storage باشد، XSS Risk مطرح می‌شود.

Browser Cookie را مدیریت می‌کند و JavaScript نمی‌تواند Token را مستقیم بخواند.

مزیت:

کاهش Token Exfiltration از طریق JavaScript.

اما:

CSRF Protection باید طراحی شود.

بنابراین هیچ انتخابی بدون Threat Model وجود ندارد.

برای Browser Applicationها اغلب BFF + HttpOnly Cookie معماری مناسبی است.

اشتباه هجدهم: ارسال JWT در URL

توکن نباید بی‌دلیل داخل Query String قرار گیرد.

مثلاً:

https://example.com/page?token=JWT

چرا؟

URL ممکن است در موارد زیر ذخیره شود:

Browser History

Web Server Log

Proxy Log

Analytics

Screenshot

Monitoring

Referrer در بعضی شرایط

OAuth Security BCP نیز یکی از دلایل کنارگذاشتن Flowهای قدیمی را کاهش Exposure توکن در Authorization Response و URL می‌داند.

JWT احراز هویت باید مانند Credential مدیریت شود.

اشتباه نوزدهم: استفاده از JWT روی HTTP

JWT Signed به معنی Encrypted Network Traffic نیست.

Bearer Token دزدیده‌شده ممکن است توسط مهاجم Reuse شود.

بنابراین انتقال Token باید روی:

HTTPS / TLS

انجام شود.

RFC 9700 نیز Access Token و Refresh Token را Secretهای حساس می‌داند که باید در Transit محافظت شوند.

Bearer Token یعنی چه؟

Bearer Token یعنی:

کسی که Token را در اختیار دارد ممکن است بتواند از آن استفاده کند.

مثل بلیت.

اگر بلیت دست فرد دیگری بیفتد، سیستم الزاماً نمی‌داند مالک اصلی چه کسی بوده است.

بسیاری از JWT Access Tokenها Bearer Token هستند.

بنابراین Token Theft اهمیت زیادی دارد.

این مشکل یکی از دلایل توسعه:

Sender-Constrained Tokens

است.

Replay Attack در JWT چیست؟

فرض کنید مهاجم Token معتبر را سرقت کرده است.

لازم نیست Token را تغییر دهد.

فقط آن را دوباره ارسال می‌کند.

Signature کاملاً معتبر است.

Claimها هم معتبرند.

اما Request از مهاجم آمده است.

این Token Replay است.

برای کاهش خطر:

  • Access Token کوتاه‌عمر باشد.
  • Audience محدود باشد.
  • Revocation وجود داشته باشد.
  • عملیات حساس Reauthentication بخواهد.
  • Sender-Constrained Token در معماری مناسب بررسی شود.

jti جلوی Replay را می‌گیرد؟

jti

به‌تنهایی نه.

jti فقط یک شناسه Token است.

برای استفاده در Replay Prevention باید Server State یا مکانیزم دیگری داشته باشد که تشخیص دهد:

این Token قبلاً Revoked شده؟

یا:

این Identifier در Context مشخص معتبر است؟

OWASP به استفاده از jti و iss در بعضی Denylistها اشاره می‌کند.

اما اگر هر Request را یک‌بارمصرف کنید، معماری بسیار Stateful می‌شود.

پس راهکار باید متناسب با Use Case باشد.

Sender-Constrained Token چیست؟

Bearer Token فقط داشتن Token را ثابت می‌کند.

Sender-Constrained Token تلاش می‌کند Token را به Client یا Key مشخصی Bind کند.

در نتیجه مهاجم علاوه بر Token باید Proof مربوط به Sender را نیز داشته باشد.

RFC 9700 برای OAuth استفاده از مکانیزم‌هایی مانند:

mTLS

و:

DPoP

را برای کاهش سوءاستفاده از Access Token دزدیده‌شده توصیه می‌کند.

این قابلیت برای هر وب‌سایت ساده‌ای ضروری نیست، اما در APIهای حساس و OAuth Architecture اهمیت دارد.

DPoP چیست؟

DPoP مخفف:

Demonstrating Proof of Possession

است.

Client یک Key Pair دارد و برای Requestها Proof امضاشده تولید می‌کند.

Token به Key Client مرتبط می‌شود.

در نتیجه کپی کردن Token به‌تنهایی همیشه برای استفاده روی Device دیگر کافی نیست.

با این حال حتی Sender-Constrained Token نیز دفاع کامل در برابر Client کاملاً Compromiseشده نیست.

RFC 9700 نیز اشاره می‌کند اگر Attacker هم Token و هم Key Material را در اختیار بگیرد، این کنترل تضعیف می‌شود.

اشتباه بیستم: Refresh Token بسیار طولانی و بدون Rotation

Access Token معمولاً عمر کوتاه دارد.

برای جلوگیری از Login مکرر، Refresh Token استفاده می‌شود.

Refresh Token می‌تواند Access Token جدید بگیرد.

به همین دلیل از Access Token حساس‌تر هم می‌تواند باشد.

اگر Refresh Token چند ماه اعتبار داشته باشد و دزدیده شود، مهاجم ممکن است مرتب Access Token جدید دریافت کند.

RFC 9700 Refresh Token را هدف جذابی برای مهاجمان می‌داند و برای Public Clientها الزام می‌کند از:

Sender-Constrained Refresh Token

یا:

Refresh Token Rotation

برای تشخیص Replay استفاده شود. Refresh Token Rotation چیست؟

Refresh Token Rotation چیست؟

در Rotation:

Refresh Token A ↓ استفاده می‌شود ↓ Access Token جدید + Refresh Token B

و Refresh Token A Invalid می‌شود.

اگر بعداً Token A دوباره استفاده شود، Server متوجه می‌شود Token قدیمی Replay شده است.

این می‌تواند نشانه Compromise باشد.

در معماری حرفه‌ای:

Rotation Family

و:

Reuse Detection

نیز در نظر گرفته می‌شوند.

Access Token و Refresh Token را یکی نکنید

این دو Purpose متفاوت دارند.

Access Token:

برای Resource Access.

Refresh Token:

برای گرفتن Access Token جدید.

Refresh Token معمولاً نباید برای API Requestهای عادی ارسال شود.

هرچه Refresh Token کمتر Exposure داشته باشد بهتر است.

Logout در JWT چرا سخت‌تر است؟

در Server-Side Session:

Server Session Record را حذف می‌کند.

تمام.

اما JWT Self-Contained ممکن است تا زمان exp بدون Server State معتبر باشد.

اگر User روی Logout کلیک کند اما JWT هنوز 30 دقیقه اعتبار داشته باشد، نسخه سرقت‌شده آن ممکن است همچنان قابل استفاده باشد.

راهکارهای متداول:

  • Access Token کوتاه‌عمر
  • Revocation List
  • Session Version
  • Refresh Token Revocation
  • Token Status Mechanism

OWASP نیز اشاره می‌کند اگر JWT برای Session استفاده شود، نیاز به Session Invalidation می‌تواند مزیت Stateless بودن را کاهش دهد.

Denylist چیست؟

Denylist فهرستی از Tokenهایی است که دیگر نباید پذیرفته شوند.

مثلاً Token با:

jti=123

تا زمان Expiration در Denylist قرار می‌گیرد.

هر Request بررسی می‌شود که آیا jti Revoked شده است یا نه.

مزیت:

Logout فوری‌تر.

عیب:

State و Lookup اضافه می‌شود.

بنابراین JWT دیگر کاملاً Stateless نیست.

آیا Blacklist کردن Hash کامل JWT مناسب است؟

باید با احتیاط انجام شود.

OWASP در راهنمای فعلی خود هشدار می‌دهد استفاده صرف از Raw JWT یا Hash آن به‌عنوان Denylist Key ممکن است در بعضی شرایط به دلیل JWT Malleability مشکل ایجاد کند و رویکرد مبتنی بر Claimهای هویتی Token مانند jti و iss می‌تواند مناسب‌تر باشد.

بنابراین Revocation Design نباید با یک Tutorial ساده اینترنتی بدون Threat Analysis پیاده شود.

اشتباه بیست‌ویکم: Access Token با Scope بیش از حد

Token باید حداقل Permission لازم را داشته باشد.

مثلاً یک Mobile Application که فقط Orderها را می‌خواند نباید Token با:

admin:*

دریافت کند.

RFC 9700 توصیه می‌کند Privilege Access Token به حداقل موردنیاز محدود و Audience نیز Restrict شود تا اثر Token Leakage کاهش پیدا کند.

اصل:

Least Privilege

در Token نیز اعمال می‌شود.

Token برای یک API خاص بهتر از Token همه‌کاره است

در Microservice Architecture گاهی یک Token برای:

User API

Billing API

Storage API

Admin API

همگی پذیرفته می‌شود.

این طراحی Blast Radius را افزایش می‌دهد.

Audience Restriction می‌تواند باعث شود هر Token فقط برای Resource Server مشخص معتبر باشد.

مثلاً:

aud=billing-api

و Billing API فقط همین Audience را قبول کند.

JWT نباید جای Database Permission Check را بگیرد

فرض کنید JWT می‌گوید:

user_id=55

و:

role=user

حالا Request می‌خواهد Invoice متعلق به User 88 را ببیند.

JWT معتبر است.

اما Server هنوز باید Object-Level Authorization را بررسی کند:

آیا User 55 اجازه Invoice 88 را دارد؟

JWT هیچ‌کدام از مشکلات:

IDOR

Broken Access Control

Missing Authorization

را خودکار حل نمی‌کند.

اشتباه بیست‌ودوم: نداشتن Reauthentication برای عملیات حساس

حتی JWT معتبر نباید برای همیشه معادل Trust کامل باشد.

مثلاً برای:

تغییر Password

غیرفعال‌کردن 2FA

تغییر Email

ساخت API Key

برداشت مالی

تغییر Permission

ممکن است Reauthentication لازم باشد.

اگر JWT دزدیده شده باشد، این کنترل خسارت را محدود می‌کند.

اشتباه بیست‌وسوم: Tokenهای بدون Typing مشخص

RFC 8725 استفاده از Explicit Typing را در JWTهایی که ممکن است با Tokenهای دیگر اشتباه گرفته شوند توصیه می‌کند.

Header:

typ

می‌تواند کمک کند Validator تشخیص دهد Token برای چه Contextی ساخته شده است.

مثلاً معماری ممکن است Typeهای جدا داشته باشد:

Access JWT

Email Verification JWT

Password Reset JWT

اگر Validation Ruleهای این Tokenها یکی باشند، Token Type Confusion ممکن است ایجاد شود.

بهتر است:

  • Type متفاوت
  • Audience متفاوت
  • Key متفاوت در صورت نیاز
  • Validation Rule متفاوت

تعریف شود.

Password Reset Token را مثل Access JWT طراحی نکنید

یک Password Reset Token Purpose بسیار محدود دارد.

نباید بتوان همان Token را به API Authentication داد.

Token Reset باید:

Audience مخصوص

Purpose مشخص

عمر بسیار کوتاه

One-Time Usage

داشته باشد.

جداسازی Purpose یکی از مهم‌ترین اصول Secure Token Design است.

JWT Key Management چگونه باید باشد؟

Cryptography فقط انتخاب Algorithm نیست.

چرخه کامل Key شامل:

Generation

Storage

Distribution

Usage

Rotation

Revocation

Destruction

است.

Private Key باید فقط در اختیار Issuer باشد.

Public Key می‌تواند از طریق JWKS منتشر شود.

در HMAC Secret باید فقط در سرویس‌هایی باشد که واقعاً باید Token تولید یا Verify کنند.

JWKS چیست؟

JWKS مخفف:

JSON Web Key Set

است.

یک Document JSON شامل Public Keyهای یک Issuer.

مثلاً Identity Provider می‌تواند Public Keyهای Active خود را از URI مشخص منتشر کند.

Resource Server با kid می‌تواند Key مناسب را از مجموعه Trusted پیدا کند.

اما Trust باید از:

Issuer Metadata معتبر

و HTTPS

آغاز شود.

نه URL دلخواهی که داخل Token آمده است.

kid چه کاربردی دارد؟

kid

Key Identifier است.

وقتی چند Signing Key وجود دارد، Token اعلام می‌کند با کدام Key امضا شده است.

Validator:

kid را می‌گیرد ↓ داخل Trusted Key Set جست‌وجو می‌کند ↓ Public Key را انتخاب می‌کند ↓ Signature را Verify می‌کند

اما kid خودش Data ورودی است و نباید مستقیماً به Query یا File Path ناامن وصل شود.

OWASP نیز به Injection Risk در Key Lookup اشاره می‌کند.

Library امنیت JWT باید چگونه انتخاب شود؟

Cryptography را از صفر پیاده‌سازی نکنید.

از Library شناخته‌شده و Maintained استفاده کنید.

مواردی که باید بررسی شوند:

  • Algorithm Allowlist
  • Claim Validation
  • Key Type Enforcement
  • JWKS Support
  • Security Advisory
  • Update History
  • Strict Parsing

Library قدیمی JWT ممکن است Vulnerabilityهای شناخته‌شده Algorithm Confusion داشته باشد.

پس Dependency Management نیز بخشی از امنیت JWT است.

JWT و Supply Chain Security

Library JWT خودش یک Dependency امنیتی حیاتی است.

اگر Package مربوط به Token Parsing یا Signature Verification آسیب‌پذیر باشد، Security کل Authentication تحت تأثیر قرار می‌گیرد.

بنابراین:

Lock File

SCA

Security Advisory

Update

Vendor Review

برای Library JWT اهمیت ویژه دارند.

امنیت JWT در WordPress

WordPress Core به‌صورت پیش‌فرض JWT را روش استاندارد Login Dashboard قرار نمی‌دهد.

مستندات رسمی WordPress می‌گویند Authentication استاندارد WordPress بر Cookie Authentication مبتنی است و REST API برای دسترسی خارجی نیز می‌تواند از Application Passwordها یا Pluginهای Authentication سفارشی استفاده کند.

بنابراین اگر در WordPress JWT مشاهده می‌کنید، معمولاً یکی از این موارد وجود دارد:

  • Plugin JWT Authentication
  • Headless WordPress
  • Mobile Application
  • Custom REST API
  • SSO Integration
  • Frontend جدا مانند React یا Next.js

در این معماری‌ها مسئولیت امنیت JWT معمولاً بر عهده Plugin یا Application سفارشی است.

JWT Plugin در WordPress چه چیزهایی باید رعایت کند؟

اگر Plugin برای WordPress JWT صادر می‌کند، بررسی کنید:

  • Secret یا Private Key چگونه ذخیره می‌شود؟
  • Algorithm ثابت و Allowlist شده است؟
  • Token exp دارد؟
  • Issuer مشخص است؟
  • Audience Validate می‌شود؟
  • User Capability بعد از Token Validation بررسی می‌شود؟
  • Refresh Token چگونه کار می‌کند؟
  • Logout و Revocation وجود دارد؟
  • Token در LocalStorage ذخیره نمی‌شود؟
  • HTTPS اجباری است؟
  • Plugin مرتب Update می‌شود؟

نصب یک Plugin با نام «JWT Authentication» به‌تنهایی به معنی امن شدن API نیست.

JWT در Headless WordPress

در Headless Architecture:

WordPress → API

Frontend → React / Vue / Next.js

است.

JWT ممکن است برای Authentication میان Frontend و API استفاده شود.

بزرگ‌ترین تصمیم‌ها:

Token کجا ذخیره شود؟

Access Token چه مدت اعتبار داشته باشد؟

Refresh Token چگونه محافظت شود؟

CSRF چگونه کنترل شود؟

XSS چگونه کنترل شود؟

Logout چگونه Revocation شود؟

برای Browser-Based Frontend بهتر است قبل از ذخیره مستقیم Token در LocalStorage، معماری BFF یا HttpOnly Cookie بررسی شود.

Application Passwordهای WordPress چه تفاوتی با JWT دارند؟

WordPress Core دارای Application Password است که Credential جداگانه و قابل Revocation برای API Integration ایجاد می‌کند.

هر Integration می‌تواند Application Password مستقل داشته باشد و Credential بدون تغییر Password اصلی User Revoked شود. مستندات رسمی WordPress نیز این قابلیت را برای API و Integrationها معرفی می‌کنند.

بنابراین برای هر Integration WordPress لزوماً لازم نیست JWT Plugin اضافه شود.

Architecture باید بر اساس نیاز انتخاب شود.

آیا JWT Stateless همیشه بهتر است؟

خیر.

Stateless بودن مزایا دارد:

Scalability

عدم Lookup Session برای هر Request

سادگی بعضی Microserviceها

اما معایب:

Logout پیچیده‌تر

Revocation پیچیده‌تر

Stale Authorization

Token Replay

Key Rotation

Refresh Token Management

اگر Application یک وب‌سایت ساده با Login معمولی است، Session Server-Side ممکن است ساده‌تر و امن‌تر باشد.

OWASP نیز توصیه می‌کند قبل از استفاده از JWT برای User Session بررسی شود آیا واقعاً مزیتی وجود دارد.

Session ID یا JWT؛ کدام امن‌تر است؟

هیچ پاسخ مطلقی وجود ندارد.

امنیت به Implementation بستگی دارد.

Session ID

مزایا:

Server کنترل کامل State دارد.

Logout ساده است.

Revocation فوری است.

Payload Client حداقل است.

معایب:

Session Storage نیاز دارد.

Distributed System نیازمند Shared Session Infrastructure است.

JWT

مزایا:

Self-Contained Claim

مناسب بعضی Distributed Architectureها

Validation محلی

معایب:

Revocation دشوارتر

Payload قابل مشاهده

Token Replay

Key Management پیچیده‌تر

بنابراین Technology Choice باید از Architecture بیاید، نه Trend.

JWT و CORS

CORS به‌خودی‌خود JWT را امن نمی‌کند.

اگر API Cross-Origin است، CORS باید Originهای مورداعتماد را کنترل کند.

اما CORS:

Authentication نیست.

Authorization نیست.

Token Validation نیست.

یک API نباید بگوید:

«چون Origin مجاز است پس Token را بررسی نمی‌کنم.»

هر Request حساس همچنان باید Authentication و Authorization صحیح داشته باشد.

JWT و XSS

اگر JWT در Browser Storage قابل دسترسی به JavaScript باشد، XSS می‌تواند خطر Token Theft ایجاد کند.

حتی اگر Token HttpOnly باشد، XSS همچنان خطرناک است و ممکن است از Session کاربر برای ارسال Request سوءاستفاده کند.

پس امنیت JWT شامل:

XSS Prevention

CSP

Output Encoding

Sanitization

Dependency Security

نیز می‌شود.

JWT و CSRF

اگر JWT در Authorization Header باشد و Browser آن را خودکار ارسال نکند، مدل CSRF متفاوت است.

اما اگر JWT داخل Cookie باشد، Browser ممکن است Cookie را خودکار ارسال کند.

در آن حالت باید:

SameSite

CSRF Token

Origin Validation

و سایر دفاع‌های متناسب بررسی شوند.

پس جمله:

«JWT جلوی CSRF را می‌گیرد»

صحیح نیست.

Storage Architecture تعیین‌کننده است.

JWT Logging؛ چه چیزی را نباید Log کنیم؟

توکن کامل JWT نباید بدون ضرورت در:

Application Log

Proxy Log

Analytics

Error Report

APM

ذخیره شود.

JWT ممکن است Credential معتبر باشد.

اگر Log Compromise شود، Token می‌تواند Replay شود.

برای Correlation بهتر است:

jti

یا Identifier غیرحساس

ثبت شود.

اگر Token نیازمند Troubleshooting است، باید Masking و Redaction وجود داشته باشد.

اطلاعات Payload هم ممکن است در Log لو برود

حتی Expired JWT ممکن است اطلاعات شخصی داخل Payload داشته باشد.

بنابراین Logging فقط Replay Risk نیست.

Privacy Risk نیز وجود دارد.

این یکی دیگر از دلایل Data Minimization در Claims است.

JWT در URL Fragment چطور؟

در بعضی Flowهای قدیمی OAuth Token در URL Fragment بازگردانده می‌شد.

OAuth 2.0 Security BCP جدید استفاده از Implicit Grant و Flowهایی که Access Token را در Authorization Response قرار می‌دهند توصیه نمی‌کند مگر در شرایط خاص و با Mitigationهای کافی؛ یکی از دلایل اصلی Token Leakage و Replay است.

برای معماری جدید معمولاً Authorization Code Flow و PKCE ترجیح داده می‌شوند.

Refresh Token باید کجا ذخیره شود؟

Refresh Token از Access Token حساس‌تر است و باید کمترین Exposure را داشته باشد.

در Browser Application، نگهداری مستقیم Refresh Token در JavaScript Storage Risk زیادی دارد.

راهکارهای معماری ممکن:

Backend-for-Frontend

HttpOnly Cookie

Secure Native Storage در Mobile

Sender-Constrained Refresh Token

بسته به Client Type.

انتخاب Storage باید بر اساس Threat Model انجام شود.

Mobile App با Browser فرق دارد

در Mobile Native Application:

Secure Storage سیستم‌عامل مانند Keychain یا Keystore ممکن است استفاده شود.

LocalStorage مسئله Browser است.

بنابراین توصیه امنیتی باید با Platform متناسب باشد.

یک راهکار واحد برای:

Browser

Mobile

Server

CLI

وجود ندارد.

مهم‌ترین سیاست اعتبارسنجی JWT

وقتی Server JWT دریافت می‌کند، اعتبارسنجی باید تقریباً به این شکل مفهومی باشد:

Token Format معتبر است؟

↓

Token Type مورد انتظار است؟

↓

Algorithm در Allowlist است؟

↓

Key متعلق به Issuer معتبر است؟

↓

Signature معتبر است؟

↓

iss معتبر است؟

↓

aud برای این Service است؟

↓

exp تمام نشده؟

↓

nbf رسیده است؟

↓

Token Revoked نیست؟

↓

Scope/Role مناسب Request است؟

↓

Authorization Resource تأیید می‌شود؟

تنها مرحله:

«Signature Valid»

برای Authentication کامل کافی نیست.

جدول مهم‌ترین اشتباهات JWT

اشتباهپیامد احتمالیکنترل دفاعی
قبول alg=noneجعل TokenAlgorithm Allowlist
Algorithm Confusionجعل SignatureKey Type Enforcement
HMAC Secret ضعیفکشف SecretRandom High-Entropy Key
نداشتن expToken طولانی‌عمرExpiration
نادیده‌گرفتن issپذیرش Issuer اشتباهIssuer Validation
نادیده‌گرفتن audToken ConfusionAudience Validation
ذخیره در LocalStorageسرقت در XSSHttpOnly Cookie/BFF
Token در URLنشت در Log/HistoryHeader یا Cookie امن
Refresh بدون RotationSession طولانی مهاجمRotation/Replay Detection
نداشتن RevocationLogout ناقصDenylist/Session State
Role طولانی‌عمردسترسی منقضی‌شدهShort TTL/Live Check
Trust به jkuKey Injection/SSRFTrusted JWKS
Payload حساسInformation DisclosureData Minimization
Scope گستردهBlast Radius بالاLeast Privilege

چک‌لیست امنیت JWT برای توسعه‌دهنده

قبل از Deploy یک سیستم JWT، این موارد را بررسی کنید:

  • آیا JWT واقعاً برای Architecture لازم است؟
  • Library معتبر و به‌روز است؟
  • Algorithmهای مجاز Hardcode یا Allowlist شده‌اند؟
  • alg=none پذیرفته نمی‌شود؟
  • MAC و Public-Key Algorithm بدون کنترل Mix نشده‌اند؟
  • HMAC Secret تصادفی و قوی است؟
  • Secret داخل Source Code نیست؟
  • Key Rotation تعریف شده است؟
  • Private Key فقط در Issuer قرار دارد؟
  • kid فقط Trusted Keyها را انتخاب می‌کند؟
  • jku و x5u Trust محدود دارند؟
  • Signature همیشه Verify می‌شود؟
  • exp Validate می‌شود؟
  • nbf Validate می‌شود؟
  • iss Validate می‌شود؟
  • aud Validate می‌شود؟
  • Token Type بررسی می‌شود؟
  • Access Token کوتاه‌عمر است؟
  • Scope حداقل است؟
  • Refresh Token امن است؟
  • Refresh Rotation وجود دارد؟
  • Logout و Revocation طراحی شده‌اند؟
  • Token داخل URL نمی‌رود؟
  • JWT کامل Log نمی‌شود؟
  • HTTPS اجباری است؟
  • XSS و CSRF بر اساس Storage Model بررسی شده‌اند؟
  • Reauthentication برای عملیات حساس وجود دارد؟
  • Authorization مستقل از Authentication اجرا می‌شود؟

چک‌لیست JWT در Browser

در Browser Application:

  • JWT را در LocalStorage ذخیره نکنید مگر Threat Model و Risk را آگاهانه پذیرفته باشید.
  • HttpOnly Cookie یا BFF را بررسی کنید.
  • Secure Cookie فعال باشد.
  • SameSite مناسب باشد.
  • CSRF Protection در Cookie-Based Auth وجود داشته باشد.
  • CSP و XSS Prevention فعال باشند.
  • Access Token کوتاه‌عمر باشد.
  • Refresh Token در JavaScript قابل دسترسی نباشد، اگر معماری اجازه می‌دهد.
  • Token کامل در Analytics ارسال نشود.
  • Third-Party Scriptها محدود باشند.

چک‌لیست JWT برای API

برای Resource Server:

  • Signature Validate شود.
  • Algorithm Allowlist باشد.
  • Issuer ثابت و Trusted باشد.
  • Audience دقیق بررسی شود.
  • Expiration بررسی شود.
  • Scope بررسی شود.
  • Authorization Object-Level اجرا شود.
  • Token Secret Log نشود.
  • HTTPS اجباری باشد.
  • Rate Limit متناسب وجود داشته باشد.
  • Token Revocation Strategy مشخص باشد.
  • عملیات حساس نیازمند Authentication Freshness باشند.

مانیتورینگ JWT چه چیزهایی را ثبت کند؟

برای Detection می‌توان این Eventها را Log کرد:

Token Validation Failure

Invalid Signature

Expired Token

Unknown Issuer

Wrong Audience

Revoked jti

Refresh Token Reuse

Unexpected Algorithm

Unknown kid

Scope Violation

Suspicious Geographic Usage

اما Token کامل نباید در Log قرار گیرد.

این Eventها برای تشخیص:

Replay

Misconfiguration

Attack

و Developer Error

ارزشمند هستند.

نشانه‌های احتمالی JWT Attack

موارد زیر نیازمند بررسی‌اند:

  • افزایش ناگهانی Signature Error
  • Token با Algorithm غیرمنتظره
  • kid ناشناس
  • Request با Issuer جدید
  • Refresh Token Reuse
  • یک JWT از Locationهای نامرتبط
  • Token قدیمی بعد از Logout
  • درخواست Admin با Token User
  • Audience mismatch زیاد
  • Token با Expiration غیرعادی طولانی

هیچ‌کدام به‌تنهایی اثبات Compromise نیستند.

Correlation اهمیت دارد.

اگر JWT Signing Key لو رفت چه کنیم؟

این Incident جدی است.

Signing Key به مهاجم اجازه می‌دهد Tokenهایی تولید کند که از نظر Cryptographic معتبر به نظر برسند.

فرآیند دفاعی:

Key را Rotate کنید

Key جدید تولید شود.

Key Compromised را Revoke کنید

Validatorها دیگر آن را قبول نکنند.

Tokenهای قدیمی را بررسی کنید

بسته به Architecture ممکن است همه Sessionها نیاز به Reauthentication داشته باشند.

Timeline را بررسی کنید

از چه زمانی Key در معرض بوده است؟

Logها را تحلیل کنید

Token یا Activity جعلی وجود داشته؟

Root Cause را اصلاح کنید

Repository؟

CI؟

Secret Manager؟

Developer Laptop؟

Backup؟

صرفاً ساخت Key جدید بدون رفع مسیر Leak کافی نیست.

اگر Access Token یک کاربر دزدیده شود چه کنیم؟

مقیاس Incident متفاوت است.

در صورت امکان:

  • Token Revoked شود.
  • Refresh Token Family باطل شود.
  • Sessionهای مربوطه بسته شوند.
  • Activity بررسی شود.
  • Credential در صورت نیاز Rotate شود.
  • User مطلع شود.
  • Root Cause مانند XSS یا Malware بررسی شود.

اگر Token فقط چند دقیقه اعتبار داشته باشد، Blast Radius کمتر از Token چندماهه است.

چرا Short-Lived Token مهم است؟

هیچ کنترل Security شکست‌ناپذیر نیست.

فرض کنیم Token در نهایت Leak شود.

اگر Token:

۵ دقیقه

عمر داشته باشد، مهاجم پنجره زمانی محدودی دارد.

اگر:

۶ ماه

عمر داشته باشد، مشکل بسیار بزرگ‌تر است.

Short TTL یک کنترل Damage Limitation است.

اما Expiration خیلی کوتاه هم مشکل دارد

اگر Access Token هر ۳۰ ثانیه Refresh شود:

Load افزایش پیدا می‌کند.

Refresh Token بیشتر استفاده می‌شود.

Complexity افزایش می‌یابد.

بنابراین TTL باید Risk-Based باشد.

Security همیشه Trade-off میان:

Risk

Performance

UX

Complexity

است.

آیا JWT می‌تواند کاملاً بدون Database باشد؟

بله، در بعضی Use Caseها.

اما اگر نیاز دارید:

Logout فوری

Revocation

Device Management

Permission Update فوری

Session Tracking

داشته باشید، معمولاً بخشی از State دوباره برمی‌گردد.

بنابراین شعار:

«JWT یعنی Database لازم نیست»

بیش از حد ساده‌سازی شده است.

JWT و Microservices

در Microserviceها JWT می‌تواند مفید باشد.

Authorization Server Token صادر می‌کند.

چند Resource Server Signature را با Public Key Verify می‌کنند.

اما باید:

Audience per Service

Scope per Service

Key Trust

Token Type

Expiration

رعایت شود.

نباید همه Microserviceها یک Shared Secret واحد داشته باشند که همه بتوانند Token Admin بسازند.

JWT داخلی هم نیاز به HTTPS دارد

گاهی Developer می‌گوید:

«این Token فقط داخل شبکه داخلی است.»

Internal Network نباید Trust Boundary مطلق فرض شود.

Microservice Traffic نیز ممکن است نیازمند:

TLS

mTLS

Service Identity

Network Policy

باشد.

Zero Trust یعنی Internal بودن به‌تنهایی Authentication نیست.

اشتباهات رایج مدیریتی درباره JWT

JWT یعنی Encryption

خیر.

JWT یعنی Stateless و Logout لازم نیست

خیر.

Signature معتبر یعنی Authorization صحیح

خیر.

JWT جلوی XSS را می‌گیرد

خیر.

JWT جلوی CSRF را می‌گیرد

وابسته به Storage Model است.

Token را یک بار صادر کنیم و یک سال معتبر باشد

برای Authentication حساس معمولاً انتخاب ضعیفی است.

Secret طولانی انسانی کافی است

Entropy مهم‌تر از ظاهر طولانی Password است.

هر JWT معتبر را می‌توان به هر API داد

Audience و Token Purpose باید کنترل شوند.

معماری دفاعی پیشنهادی برای JWT

یک معماری مناسب را می‌توان در هفت لایه دید.

لایه اول: Authentication

Login امن

2FA

Rate Limiting

Credential Protection

لایه دوم: Issuance

Issuer معتبر

Claim حداقلی

Audience مشخص

Expiration کوتاه

لایه سوم: Cryptography

Algorithm Allowlist

Strong Key

Key Rotation

Trusted JWKS

لایه چهارم: Transport و Storage

HTTPS

Secure Storage

HttpOnly Cookie یا BFF در Browser

عدم ذخیره در URL و Log

لایه پنجم: Validation

Signature

Issuer

Audience

Expiration

Token Type

Scope

لایه ششم: Lifecycle

Refresh Rotation

Revocation

Logout

Reauthentication

لایه هفتم: Monitoring

Invalid Token Alert

Refresh Reuse Detection

Key Usage Monitoring

Security Logging

این معماری نشان می‌دهد امنیت JWT فقط یک Function:

verify(token)

نیست.

سؤالات متداول درباره امنیت JWT

JWT چیست؟

JWT یا JSON Web Token قالب استانداردی برای انتقال مجموعه‌ای از Claimهاست که می‌تواند امضا و در بعضی ساختارها رمزگذاری شود. JWT در APIها، OAuth، OpenID Connect و بعضی سیستم‌های احراز هویت استفاده می‌شود.

آیا JWT رمزگذاری شده است؟

JWT Signed معمولی رمزگذاری نشده است. Header و Payload معمولاً Base64URL هستند و قابل Decode شدن‌اند. Signature فقط از تغییر غیرمجاز محتوا جلوگیری می‌کند.

آیا JWT امن است؟

JWT در صورت Implementation صحیح می‌تواند امن باشد، اما انتخاب اشتباه Algorithm، Key ضعیف، Token Lifetime طولانی، Storage ناامن و Validation ناقص می‌تواند امنیت آن را از بین ببرد.

alg=none چیست؟

alg=none نوعی JWT بدون Signature است که استاندارد برای Use Caseهای خاص تعریف کرده، اما سیستم Authentication نباید آن را در جایی که Signature لازم است بپذیرد.

HS256 بهتر است یا ES256؟

هر دو می‌توانند در Context مناسب امن باشند. HS256 از Shared Secret استفاده می‌کند، در حالی که ES256 Public/Private Key دارد. برای سیستم‌های Distributed، Public-Key Signature اغلب Key Distribution و Security Boundary بهتری ایجاد می‌کند.

JWT را در LocalStorage ذخیره کنیم؟

OWASP در راهنمای فعلی Session Management توصیه می‌کند Authentication Token، JWT و Refresh Token در LocalStorage یا SessionStorage ذخیره نشوند، زیرا JavaScript در Origin می‌تواند آن‌ها را بخواند و XSS باعث Token Theft شود.

JWT چطور Logout می‌شود؟

در JWT Stateless صرف حذف Token از Client نسخه دزدیده‌شده را باطل نمی‌کند. معماری می‌تواند از Access Token کوتاه‌عمر، Refresh Token Revocation، Denylist یا Session State برای Logout و Revocation استفاده کند.

آیا WordPress به‌طور پیش‌فرض JWT دارد؟

خیر. WordPress Core برای Login استاندارد از Cookie Authentication استفاده می‌کند. JWT معمولاً از طریق Plugin یا معماری Headless و Custom REST API اضافه می‌شود.

جمع‌بندی؛ چگونه امنیت JWT را افزایش دهیم؟

JWT ابزار قدرتمندی است، اما Security Feature جادویی نیست.

وجود سه بخش:

Header.Payload.Signature

به این معنی نیست که Authentication شما خودبه‌خود امن است.

امنیت JWT از مجموعه‌ای از تصمیم‌ها تشکیل می‌شود:

Algorithm چه باشد؟

Key چقدر قوی باشد؟

چه کسی Issuer است؟

Token برای چه Audienceای صادر شده؟

چقدر عمر دارد؟

کجا ذخیره می‌شود؟

چگونه Refresh می‌شود؟

چگونه Logout می‌شود؟

و اگر Token یا Key لو رفت، چگونه آن را Revocation می‌کنیم؟

مهم‌ترین اصل این است که Validator نباید Security Policy را از Token دریافتی یاد بگیرد.

Algorithm، Issuer، Audience و Trusted Key باید سمت Server از قبل مشخص باشند.

RFC 8725 دقیقاً بر همین موضوع تأکید می‌کند: Algorithmهای قابل قبول باید کنترل شوند، Key Strength کافی باشد و Issuer و Audience اعتبارسنجی شوند.

Access Token نیز باید Credential حساس در نظر گرفته شود.

توکن دزدیده‌شده ممکن است بدون شکستن Password یا 2FA قابل Replay باشد.

به همین دلیل:

HTTPS + Access Token کوتاه‌عمر + Scope محدود + Audience محدود + Refresh Token Rotation + Revocation + Reauthentication

مدل بسیار امن‌تری از Token طولانی‌عمر بدون Lifecycle Management ایجاد می‌کند.

برای Browser نیز باید Storage بسیار جدی گرفته شود.

قرار دادن JWT و Refresh Token داخل LocalStorage ساده است، اما XSS می‌تواند آن‌ها را در معرض سرقت قرار دهد. استفاده از HttpOnly Cookie یا معماری Backend-for-Frontend در بسیاری از برنامه‌های Browser-Based گزینه‌ای است که ارزش بررسی جدی دارد.

همچنین JWT جایگزین Authorization نیست.

حتی پس از Validate شدن Token باید مشخص شود User برای همان Object و همان Action Permission دارد.

در WordPress نیز نباید صرفاً برای مدرن‌تر به‌نظر رسیدن Authentication یک JWT Plugin نصب کرد. WordPress Core روش‌های استاندارد خود مانند Cookie Authentication و Application Passwords را دارد و اضافه‌کردن JWT باید یک تصمیم معماری باشد، نه یک الزام عمومی.

در نهایت می‌توان امنیت JWT را در یک جمله خلاصه کرد:

JWT زمانی امن است که نه‌فقط Signature، بلکه کل چرخه عمر Token از صدور تا ذخیره، اعتبارسنجی، Refresh، Revocation و Authorization به‌صورت سخت‌گیرانه طراحی شده باشد.

مطالب مرتبط