امنیت 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 امضاشده یا 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 از لحظه صدور 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 یا 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 مربوط به
kidSanitization داشته باشد.
اشتباه نهم: فقط 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
بررسی شوند. 
آیا HttpOnly Cookie همیشه بهترین گزینه است؟
برای بسیاری از 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 را توصیه میکند.
JWT در Cookie یا Authorization Header؟
دو الگوی رایج وجود دارد.
Authorization Header
Client Token را مثلاً با:
Authorization: Bearer <token>
ارسال میکند.
مزیت:
Browser خودکار Token را Cross-Site ارسال نمیکند.
اما اگر Token در JavaScript Storage باشد، XSS Risk مطرح میشود.
HttpOnly Cookie
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 چیست؟
در 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 | جعل Token | Algorithm Allowlist |
| Algorithm Confusion | جعل Signature | Key Type Enforcement |
| HMAC Secret ضعیف | کشف Secret | Random High-Entropy Key |
نداشتن exp | Token طولانیعمر | Expiration |
نادیدهگرفتن iss | پذیرش Issuer اشتباه | Issuer Validation |
نادیدهگرفتن aud | Token Confusion | Audience Validation |
| ذخیره در LocalStorage | سرقت در XSS | HttpOnly Cookie/BFF |
| Token در URL | نشت در Log/History | Header یا Cookie امن |
| Refresh بدون Rotation | Session طولانی مهاجم | Rotation/Replay Detection |
| نداشتن Revocation | Logout ناقص | Denylist/Session State |
| Role طولانیعمر | دسترسی منقضیشده | Short TTL/Live Check |
Trust به jku | Key Injection/SSRF | Trusted JWKS |
| Payload حساس | Information Disclosure | Data 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وx5uTrust محدود دارند؟- Signature همیشه Verify میشود؟
expValidate میشود؟nbfValidate میشود؟issValidate میشود؟audValidate میشود؟- 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 بهصورت سختگیرانه طراحی شده باشد.