JWT
2 ابزار
مبانی امنیت وب
امنیت وب به معنای حفاظت از برنامههای وب و APIها در برابر دسترسی غیرمجاز، نشت داده و حملات است. برنامههای مدرن از احراز هویت (اثبات هویت)، مجوزدهی (اثبات دسترسیها) و رمزنگاری برای اعمال مرزهای امنیتی استفاده میکنند.
JSON Web Tokens (JWT) مکانیزم غالب احراز هویت بدون وضعیت در توسعه وب مدرن هستند. درک نحوه کارکرد JWTها — شامل ساختار، الگوریتمهای امضا و آسیبپذیریها — برای ساخت APIها و برنامههای امن ضروری است.
JSON Web Tokens (JWT)
JWT روشی فشرده و URL-safe برای نمایش ادعاها بین دو طرف است. از سه بخش Base64url-encoded جدا شده با نقطه تشکیل شده است. JWTها میتوانند بدون جستجو در پایگاه داده تأیید شوند زیرا امضا کل توکن را پوشش میدهد.
سه بخش یک JWT
حاوی متادیتای توکن است: الگوریتم امضا (alg) و نوع توکن (typ). همیشه JSON با رمزگذاری Base64url است. انتخاب الگوریتم در اینجا بر امنیت کل توکن تأثیر میگذارد.
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9{
"alg": "HS256",
"typ": "JWT"
}حاوی ادعاها است: اطلاعاتی درباره کاربر و متادیتای اضافی. همچنین JSON با رمزگذاری Base64url است. هر کسی میتواند این بخش را رمزگشایی کند — دادههای payload رمزگذاری نشدهاند، فقط امضا شدهاند.
eyJzdWIiOiJ1c2VyXzEyMyIsInJvbGUiOiJhZG1pbiIsImV4cCI6MTcxNzIwMDAwMH0{
"sub": "user_123",
"role": "admin",
"exp": 1717200000
}یک امضای رمزنگاری بر روی header و payload رمزگذاریشده است. تأیید این امضا تضمین میکند که توکن دستکاری نشده است. کلید مخفی (HMAC) یا کلید خصوصی (RSA/ECDSA) هرگز در توکن گنجانده نمیشود.
SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5cHMACSHA256( base64url(header) + "." + base64url(payload), secret )
ادعاهای استاندارد JWT
مشخصات JWT نامهای ادعای استاندارد را تعریف میکند. استفاده از آنها قابلیت همکاری بین کتابخانهها و سرویسهای مختلف JWT را تضمین میکند:
| ادعا | نام | توضیح |
|---|---|---|
| iss | Issuer | اصلی که توکن را صادر کرده شناسایی میکند (مثلاً URL سرور احراز هویت شما) |
| sub | Subject | اصلی که موضوع توکن است شناسایی میکند (مثلاً شناسه کاربر) |
| aud | Audience | گیرندگانی که توکن برای آنها در نظر گرفته شده را شناسایی میکند (مثلاً URL API شما) |
| exp | Expiration | زمان انقضای توکن به صورت Unix timestamp — بعد از این زمان توکن دیگر معتبر نیست |
| nbf | Not Before | زمان فعالسازی توکن به صورت Unix timestamp — قبل از این زمان توکن نباید پذیرفته شود |
| iat | Issued At | زمان صدور توکن به صورت Unix timestamp — برای تعیین عمر توکن استفاده میشود |
| jti | JWT ID | شناسه یکتا برای توکن، برای جلوگیری از حملات replay توکن استفاده میشود |
الگوریتمهای امضا
الگوریتم امضا در header JWT اعلام میشود. انتخاب الگوریتم مناسب برای موارد استفادهتان برای امنیت حیاتی است:
HS256 / HS384 / HS512متقارن (HMAC)از یک کلید مخفی مشترک هم برای امضا و هم برای تأیید استفاده میکند. پیادهسازی ساده اما نیاز دارد همه تأییدکنندگان کلید مخفی را بدانند.
RS256 / RS384 / RS512نامتقارن (RSA)از کلید خصوصی برای امضا و کلید عمومی برای تأیید استفاده میکند. کلید خصوصی هرگز سرور احراز هویت را ترک نمیکند.
ES256 / ES384 / ES512نامتقارن (ECDSA)مانند RSA اما با کلیدهای کوچکتر و امضای سریعتر. امنیت معادل با عملکرد بهتر ارائه میدهد.
"alg": "none"بدون امضا — خطرناکاصلاً هیچ امضایی ندارد. توکنی با alg:none هیچ تضمین یکپارچگی ندارد و میتواند توسط هر کسی جعل شود.
جریانهای احراز هویت
- 1.کاربر نام کاربری و رمز عبور را به endpoint ورود ارسال میکند
- 2.سرور اعتبارنامهها را در برابر پایگاه داده کاربران اعتبارسنجی میکند
- 3.سرور یک JWT با ادعاهای کاربر و زمان انقضا امضا میکند
- 4.کلاینت JWT را ذخیره میکند (localStorage، کوکی یا حافظه)
- 5.کلاینت JWT را در header Authorization: Bearer برای درخواستهای بعدی ارسال میکند
- 1.کلاینت کاربر را با code challenge به سرور مجوز هدایت میکند
- 2.کاربر احراز هویت میکند و برنامه کلاینت را مجاز میکند
- 3.سرور احراز هویت با یک کد مجوز یکبار مصرف بازمیگردد
- 4.کلاینت کد + verifier را با توکنهای دسترسی و refresh مبادله میکند
- 5.کلاینت از توکن دسترسی برای فراخوانیهای API و از refresh token برای تجدید استفاده میکند
آسیبپذیریهای رایج JWT
JWTها وقتی به درستی پیادهسازی شوند امن هستند. اینها رایجترین اشتباهات پیادهسازی هستند که به آسیبپذیریهای امنیتی منجر میشوند:
برخی کتابخانهها توکنهایی با alg:none (بدون امضا) میپذیرند. یک مهاجم میتواند payload را تغییر داده و alg را به none تنظیم کند تا هر JWT را جعل کند. همیشه الگوریتم مجاز را به صراحت مشخص و اعتبارسنجی کنید.
اگر یک کتابخانه انتظار تأیید RS256 را داشته باشد اما HS256 را هم بپذیرد، یک مهاجم میتواند با استفاده از کلید عمومی به عنوان secret در HMAC توکنی امضا کند. کتابخانه آن را با موفقیت تأیید میکند. همیشه الگوریتم مورد انتظار را مشخص نگه دارید.
یک JWT بدون ادعای exp، یا کدی که exp را بررسی نمیکند، اجازه میدهد توکنها پس از خروج یا مسدود شدن کاربر بهطور نامحدود استفاده شوند. همیشه زمانهای انقضای کوتاه تنظیم کنید و ادعای exp را اعتبارسنجی کنید.
payload های JWT با Base64 رمزگذاری شدهاند، نه رمزگذاری واقعی. هر کسی که یک JWT را دریافت کند میتواند payload را رمزگشایی و بخواند. هرگز رمز عبور، شماره کارت اعتباری یا سایر اسرار را در ادعاهای JWT ذخیره نکنید.
JWTهای امضاشده با HMAC با اسرار کوتاه یا قابل پیشبینی میتوانند به صورت آفلاین brute-force شوند. یک مهاجم که یک JWT را به دست آورد میتواند میلیاردها کلید در ثانیه امتحان کند. از اسرار تصادفی رمزنگاری با حداقل ۲۵۶ بیت استفاده کنید.
قبول کردن JWT بدون بررسی امضا یعنی اعتماد کامل به محتوای payload. این یک باگ حیاتی است که به هر کاربری اجازه میدهد ادعاهای دلخواه بسازد. همیشه قبل از اعتماد به هر ادعایی امضا را تأیید کنید.
سؤالات متداول
JWTهای استاندارد (JWS — JSON Web Signature) امضا شدهاند اما رمزگذاری نشدهاند. payload با Base64url رمزگذاری شده که به سادگی قابل برگشت است. هر کسی که یک JWT داشته باشد میتواند محتوای آن را بخواند. JWE (JSON Web Encryption) رمزگذاری واقعی ارائه میدهد اما بسیار کمتر رایج است.
توکنهای دسترسی باید کوتاهمدت باشند: ۵ تا ۶۰ دقیقه معمول است. توکنهای طولانیمدت خطرناک هستند زیرا بدون یک لیست مسدود توکن نمیتوانند باطل شوند. از refresh tokenها (طولانیمدتتر، با ذخیرهسازی امن) برای دریافت توکنهای دسترسی جدید استفاده کنید.
کوکیهای HttpOnly امنترین گزینه هستند — برای JavaScript غیرقابل دسترسی هستند و از سرقت XSS جلوگیری میکنند. localStorage در برابر حملات XSS آسیبپذیر است اما از CSRF جلوگیری میکند. حافظه (متغیر JavaScript) امنترین است اما پس از reload صفحه باقی نمیماند. هیچ گزینه کاملی وجود ندارد.
نه بدون وضعیت سمت سرور. ماهیت بدون وضعیت JWTها به این معناست که سرور نمیتواند آنها را باطل کند. راهحلها: زمانهای انقضای کوتاه، یک لیست مسدود توکن (Redis)، چرخش refresh tokenها، یا تغییر به توکنهای session مات برای عملیات حساس.
کوکیهای session یک شناسه session تصادفی ذخیره میکنند؛ سرور دادههای session را جستجو میکند. JWTها خودکفا هستند — سرور امضا را بدون جستجوی پایگاه داده اعتبارسنجی میکند. JWTها در چندین سرور بهتر مقیاسپذیر هستند اما بدون زیرساخت اضافی نمیتوانند باطل شوند.
حداقل: sub (شناسه کاربر)، exp (انقضا) و iat (زمان صدور). برای راهاندازیهای چند سرویسه iss (صادرکننده) اضافه کنید. payloadها را کوچک نگه دارید — JWTها با هر درخواست ارسال میشوند. دادههای حساس یا آبجکتهای بزرگ پروفایل را در ادعاها قرار ندهید.
RS256 (نامتقارن) برای اکثر سیستمهای تولید بهتر است زیرا فقط سرور احراز هویت به کلید خصوصی نیاز دارد. سرویسهای متعدد میتوانند با استفاده از کلید عمومی توکنها را بدون اشتراکگذاری secret تأیید کنند. HS256 سادهتر است اما نیاز دارد همه تأییدکنندگان secret مشترک را بدانند.
PKCE (Proof Key for Code Exchange) یک افزونه برای جریان کد مجوز OAuth2 است که از حملات دزدیدن کد مجوز جلوگیری میکند. برای کلاینتهای عمومی (SPAها، برنامههای موبایل) که نمیتوانند client secret را به صورت امن ذخیره کنند الزامی است.