Sat, Apr 26, 2025

JWT امن نیست؟ حقیقتی که کمتر کسی به شما می‌گوید

خواه یک برنامه نویسی تازه کار هستی یا در راه یادگیری مباحث امنیتی و یا اینکه سالها هست تو این حوزه فعالیت میکنی این مطلب مناسب شماست ، چون قراره یکجورایی jwt را به چالش بکشم . در نهایت این انتخاب با شماست که برای امنیت کاربران چه راه حلی را برمیگزینید.

why JWT is not secure

JWT چیه و چرا محبوب شده؟

JWT یا JSON Web Token یک استاندارد برای انتقال اطلاعات بین دو طرف به صورت فشرده و قابل اطمینان است.
توکن‌های JWT از سه بخش ساخته شده‌اند:
Header.Payload.Signature

<base64url(header)>.<base64url(payload)>.<base64url(signature)>

اما مهم است بدانید:
JWT به خودی خود اطلاعات را رمزنگاری نمی‌کند، بلکه تنها تضمین می‌کند که محتوا تغییر نکرده.
هرکسی که به توکن دسترسی داشته باشد، می‌تواند محتوای آن را مشاهده کند.

دلیل محبوبیت JWT چیه؟

سادگی و سبکی: فرمت JSON باعث شده کار با آن آسان و سریع باشد.
استقلال از سرور: نیازی به ذخیره وضعیت کاربر روی سرور نیست (stateless).
قابل استفاده در اپلیکیشن‌های موبایل و وب: بدون نیاز به مدیریت session‌های پیچیده.
سازگاری با معماری‌های مدرن: مثل microservices و serverless.


آیا امضای دیجیتال یعنی امنیت کامل؟

خیر. امضای دیجیتال به تنهایی به معنای امنیت کامل نیست.

امضای دیجیتال در JWT (و به طور کلی در سیستم‌های رمزنگاری) فقط یک چیز را تضمین می‌کند:
👈 داده‌هایی که دریافت شده‌اند، در طول مسیر تغییر نکرده‌اند.

به زبان ساده، امضا کمک می‌کند تا مطمئن شویم:

اما امضای دیجیتال نمی‌تواند:


یک مثال ساده

فرض کنید شما یک نامه را امضا می‌کنید.
این امضا ثابت می‌کند که شما نویسنده نامه هستید و متن نامه تغییر نکرده.
اما اگر کسی نامه‌ی امضاشده‌ی شما را بدزدد، همچنان می‌تواند آن را بخواند یا از آن سوءاستفاده کند.
امضا نمی‌تواند جلوی دزدیده شدن یا خوانده شدن نامه را بگیرد.


در دنیای JWT هم همینطور است:


بررسی دقیق تر یک توکن

حال که فهمیدیم توکن چیست و از چه بخشهایی تشکیل شده و درنهایت متوجه شدید امضای دیجیتال چیست و چه مزایا و محدودیتهایی دارد میخواهم یک توکن بسازم و آنرا امضا کنم . قرار است بررسی کنیم که چه اطلاعاتی را میتوانم داخل آن نگه داری کنم بهتر است از چه کلمه رمز یا همان سیکرت کی استفاده کنم و با چه الگوریتمی آن را امضا کنم و چگونه این امضا شکل میگیرد و حتی تایید میشود ؟

برای اینکار میتوانید از یک سرویس آنلاین ساخت توکن های jwt استفاده کنید. من معمولا از سایت jwt.io استفاده میکردم اما متاسفانه به دلیل تغییراتی که در UI این سایت دادند من نتوانستم از طریق این سرویس توکن بسازم مجبور شدن از

از سرویس سایت http://jwtbuilder.jamiekurtz.com/ استفاده کردم.
با این حال، این توکن را با موفقیت ایجاد کردم.

eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJPbmxpbmUgSldUIEJ1aWxkZXIiLCJpYXQiOjE3NDU2NzY1MjMsImV4cCI6MTc3NzIxMjUyMywiYXVkIjoid3d3LmJhYmFrLnVrIiwic3ViIjoidXNlcjEiLCJHaXZlbk5hbWUiOiJCYWJhayIsIlN1cm5hbWUiOiJKYWhhbiIsIlJvbGUiOiJBZG1pbiJ9.ijKxNJgTDwuZnObIeZKvkoJkvalFfD1c7d_pcO0kBmk

این توکن در زمان ساخت یه توکن معتبر بوده و تا تاریخ انقضای موجود در آن معتبر میباشد. البته بستگی دارد که استفاده کننده این توکن کیست و تایید کننده امضا چه کسی است .

قسمتهای این توکن در تصویر زیر جدا سازی شده اند تا شما بهتر با آن آشنا شوید.

JWT TOKEN STRUCTURE

در قسمت هدر نوع الگوریتمی که امضای این توکن با آن رمزنگاری شده است را میبینید. این به استفاده کننده و دارنده کلمه رمز توکن (نه رمز کاربر وب سایت) میگوید که اصالت این توکن را با این الگوریتم اعتبار سنجی کن.

صادر کننده توکن Online JWT Builder است برای کاربران سایت www.babak.uk صادر شده است . نام کاربر اینجا user1 به عنوان مثال درج شده است. و اسم وفامیل خودم و نقش کاربری من مشخص شده است.

هیچ اشاره ایی به کلمه رمز مدیر وب سایت نشده است و هیچگونه اطلاعات دیگری از من وجود ندارد.

کار اشتباهیی که برخی از توسعه دهندگان انجام میدهند این است که پسورد کاربر را در توکن نگه داری میکنند چون گمان میکنند این توکن رمز گذاری شده است .

نحوه امضای توکن JWT

در این توکن، عملیات امضای دیجیتال با استفاده از الگوریتم HS256 انجام شده است.
HS256 مخفف HMAC با الگوریتم SHA-256 است و یک روش امضای متقارن محسوب می‌شود.
در این روش، همان کلید (SecretKey) برای هم امضا کردن و هم اعتبارسنجی امضا استفاده می‌شود.

فرمول کلی امضا به این صورت است:

HMAC_SHA256(Base64UrlEncode(header) + “.” + Base64UrlEncode(payload), SecretKey)

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

من برای ساخت این توکن از سیکرت کی babak استفاده کرده ام . پس هر کسی که این کلید مخفی را داشته باشد میتواند یک توکن برای خودش بسازد یا بهتر بگم جعل کند.


پس متوجه شدیم که :

عملیات HS256 باعث رمزنگاری (encryption) داده‌ها نمی‌شود.
بلکه فقط یک امضای دیجیتال (digital signature) ایجاد می‌کند تا تضمین شود که محتوای توکن در طول مسیر تغییر نکرده است.

چگونه اصالت این توکن تایید میشود

سرور Authorization پس از دریافت توکن، آن را به سه بخش Header، Payload و Signature تقسیم می‌کند.
سپس با استفاده از کلید محرمانه‌ی خود (یا کلید عمومی در روش‌های غیرمتقارن)، بر روی ترکیب Header و Payload یک امضای جدید ایجاد می‌کند.
اگر این امضا با امضای دریافتی مطابقت داشت، اصالت توکن تایید می‌شود.

در این فرآیند نیازی به جستجوی بانک اطلاعاتی برای تایید توکن نیست.
البته ممکن است سرور برای بررسی اطلاعات تکمیلی کاربر (مانند نقش یا وضعیت فعال بودن) پس از تایید توکن به بانک اطلاعاتی مراجعه کند.

Stateless یا Stateful بودن اعتبارسنجی توکن

اگر سرور برای تایید معتبر بودن توکن نیازی به مراجعه به پایگاه داده نداشته باشد
(فقط با بررسی امضا تصمیم بگیرد که توکن معتبر است یا خیر)، به این روش اعتبارسنجی Stateless گفته می‌شود.

در مقابل، اگر سرور برای بررسی اطلاعات بیشتر (مثل وضعیت کاربر، لغو توکن، یا نقش‌های به‌روز شده)
نیاز داشته باشد به پایگاه داده یا یک سیستم خارجی متصل شود، به آن اعتبارسنجی Stateful می‌گویند.

آیا SecretKey امنیت توکن را تضمین می‌کند؟

SecretKey نقش بسیار مهمی در تضمین امنیت امضای JWT دارد.
اما صرف داشتن یک SecretKey به تنهایی امنیت کامل را تضمین نمی‌کند؛
میزان امنیت توکن کاملاً وابسته به قدرت و نحوه مدیریت این کلید است.


اهمیت طول و پیچیدگی SecretKey

طول SecretKey باید به اندازه‌ی کافی بزرگ و تصادفی باشد.
یک SecretKey کوتاه یا ساده می‌تواند در برابر حملات مختلف آسیب‌پذیر باشد.


حملاتی که ممکن است SecretKey را فاش کنند

✅ در صورتی که SecretKey ضعیف باشد یا نشت کند، انواع حملات زیر قابل وقوع است:


دلیل بعدی که باعث عدم امنیت JWT میشود را نیز فهمیدیم لذا:

SecretKey زمانی امنیت توکن را تضمین می‌کند که طولانی، پیچیده، مخفی و به درستی مدیریت شود.
ضعف در انتخاب یا نگهداری SecretKey می‌تواند امنیت کل سیستم را به خطر بیندازد.

چگونه از SecretKey محافظت کنیم؟


حملات واقعی: سرقت توکن و Replay Attack

با وجود امضای دیجیتال در JWT، همچنان خطرهایی وجود دارد که اگر توکن به دست افراد غیرمجاز برسد، می‌تواند امنیت سیستم را به خطر بیندازد.
یکی از این خطرات سرقت توکن (Token Theft) و در ادامه‌ی آن حمله‌ی تکرار (Replay Attack) است.


سرقت توکن (Token Theft)

سرقت توکن زمانی اتفاق می‌افتد که یک شخص مهاجم به هر دلیلی بتواند نسخه‌ای از JWT شما را به دست آورد.
این سرقت می‌تواند به روش‌های مختلفی رخ دهد:

مهاجم پس از سرقت توکن می‌تواند خودش را به جای کاربر اصلی جا بزند و به منابع محافظت‌شده دسترسی پیدا کند.


حمله‌ی تکرار (Replay Attack)

پس از سرقت توکن، مهاجم می‌تواند بدون نیاز به شکستن امضا،
توکن را در درخواست‌های جدید استفاده کند و به سیستم دسترسی پیدا کند.
این کار بدون تغییر در توکن انجام می‌شود و چون امضا معتبر است، سرور درخواست را قانونی فرض می‌کند.

این نوع حمله به ویژه در مواردی خطرناک است که:


چگونه از سرقت و حملات Replay جلوگیری کنیم؟

✅ استفاده از HTTPS برای تمام ارتباطات شبکه
✅ ذخیره‌ی امن توکن‌ها با HttpOnly Cookies (نه LocalStorage)
✅ محدود کردن عمر توکن با exp کوتاه (مثلاً ۱۵ دقیقه)
✅ استفاده از Refresh Token با اعتبار کوتاه به همراه Access Token
✅ پیاده‌سازی شناسایی ناهنجاری (مثلاً شناسایی استفاده همزمان از یک توکن از مکان‌های مختلف)


این سری از نکاتی که نیز باعث عدم امنیت JWT میشود را متوجه شدیم پس نتیجه میگیریم.

امضای دیجیتال JWT جلوی تغییر محتوا را می‌گیرد، اما جلوی دزدیده شدن یا سوءاستفاده از توکن را نمی‌گیرد.
برای امنیت واقعی، باید توکن را به خوبی محافظت کرد و از روش‌های دفاعی مناسب استفاده نمود.

رمزنگاری JWT: کی لازم می‌شود؟

فهمیدیم که JWT به طور پیش‌فرض رمزنگاری نمی‌شوند، بلکه فقط امضا می‌شوند.
امضا تنها اطمینان می‌دهد که محتوا دستکاری نشده است، اما محتوای توکن همچنان برای هرکسی که به آن دسترسی داشته باشد قابل خواندن است.

اگر توکن حاوی اطلاعات حساس باشد، فقط امضا کردن کافی نیست.
در چنین شرایطی، نیاز به رمزنگاری داریم تا محتوای توکن نیز برای اشخاص غیرمجاز قابل مشاهده نباشد.


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

✅ وقتی که توکن شامل اطلاعات حساس باشد، مانند:

در این مواقع، برای حفظ محرمانگی (Confidentiality) داده‌ها باید توکن رمزنگاری شود.


چگونه JWT را رمزنگاری می‌کنیم؟

برای رمزنگاری JWT، به جای JWT معمولی (امضاشده) از JWE استفاده می‌شود.
JWE مخفف JSON Web Encryption است و فرآیند آن به شکل زیر است:


تفاوت JWT معمولی (JWS) و JWT رمزنگاری شده (JWE)

ویژگی JWS (JWT امضاشده) JWE (JWT رمزنگاری شده)
محرمانگی داده ❌ خیر ✅ بله
تغییرناپذیری داده ✅ بله ✅ بله
استفاده معمول احراز هویت (Authentication) انتقال داده‌های حساس

اگر تنها دغدغه شما تغییر نکردن داده است، امضا کافیست.
اما اگر داده‌های حساس دارید که باید از دید افراد دیگر مخفی بماند، نیاز به رمزنگاری (JWE) خواهید داشت.


نتیجه‌گیری

رمزنگاری JWT فقط زمانی لازم است که محتوای توکن شامل اطلاعات حساس باشد.
در غیر این صورت، امضا برای تضمین عدم تغییر داده کافی است.

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

کار با JWT در ظاهر ساده به نظر می‌رسد، اما خیلی وقت‌ها یک اشتباه کوچک می‌تواند امنیت کل سیستم را به خطر بیندازد.
بذار بگم چه اشتباهات معمولی رخ میده که امنیت نرم افزار یا اپلیکیشن شما به خطر میوفته.


۱. فکر کردن اینکه JWT رمزنگاری شده است

بعضی‌ها فکر می‌کنند چون توکن JWT یه شکلی رمزگونه داره، پس اطلاعاتش مخفی شده.
نه عزیزم، اطلاعات داخل JWT کاملاً قابل دیدن هست!
فقط امضا شده که دستکاری نشه، ولی هرکسی که توکن رو داشته باشه، می‌تونه محتوای اون رو ببینه.


۲. استفاده از SecretKey ضعیف

یکی از اشتباهات خیلی خطرناک اینه که یه کلمه ساده مثل password123 رو به عنوان SecretKey انتخاب کنی.
اینو مهاجما خیلی راحت با Dictionary Attack پیدا می‌کنن و بعد می‌تونن هر توکنی که دلشون بخواد بسازن!


۳. نگه داشتن توکن در LocalStorage بدون HttpOnly

خیلی‌ها میان توکن رو مستقیم تو LocalStorage ذخیره می‌کنن.
خب اگه سایتت یه آسیب‌پذیری XSS داشته باشه، هرکی می‌تونه توکن رو بدزده و به اسم کاربر لاگین کنه.
بهتره توکن رو داخل کوکی HttpOnly و Secure ذخیره کنی که جاوااسکریپت نتونه دست بزنه بهش.


۴. نذاشتن تاریخ انقضا (exp)

بعضی‌ها توکن می‌سازن ولی تاریخ انقضا (Expiration) برایش تعیین نمی‌کنن.
نتیجه این میشه که توکن برای همیشه معتبر میمونه و اگه کسی بدزدش، هر وقت بخواد می‌تونه ازش استفاده کنه.
حتماً یه مدت زمان منطقی برای انقضا بذار، مثلاً ۱۵ دقیقه برای Access Token.


۵. اعتبارسنجی نکردن امضا

فقط اینکه توکن رو از کلاینت بگیری و Payload رو بخونی کافی نیست!
باید امضای توکن رو بررسی کنی تا مطمئن بشی که تغییر نکرده و از یه منبع معتبر اومده.
هرگز Payload رو بدون تایید Signature قبول نکن.


۶. استفاده نکردن از HTTPS

رفتی کلی زحمت کشید ولی آخرش داری از همون پرتکل HTTP استفاده میکنی ؟ اگر سایتت با HTTP کار کنه (بدون SSL/TLS)، کل داده‌ها، از جمله JWT، به صورت متن ساده (Plaintext) روی شبکه منتقل میشه!
مهاجما خیلی راحت میتونن با حملاتی مثل MITM (Man-In-The-Middle) توکن رو سرقت کنن.
حتماً باید تمام ترافیک سایت مخصوصاً قسمت‌هایی که JWT رد و بدل میشه رو روی HTTPS ایمن کنی.


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

منبع اصلی این نکات، استاندارد RFC 7519 است که یک مرجع رسمی برای ساخت و کار با JWT محسوب می‌شود. به علاوه، تجربیات شخصی خودم و مطالبی که طی این سال‌ها خوانده‌ام را هم سعی کردم به صورت جامع و منظم ارائه بدهم.

محتوای خوب فارسی در مورد این مباحث واقعاً کم است (فکر کنم شما هم قبول دارید)،
و هنوز هم خیلی چیزهای دیگر درباره JWT وجود دارد که ننوشته‌ام و قصد دارم به تدریج منتشر کنم.


اگر درباره نحوه پیاده‌سازی و کدنویسی سوال داشتی

من یک گروه تلگرامی دارم که نزدیک به دو سال است راه‌اندازی شده و در آن درباره FastAPI و موضوعات مرتبط بحث می‌کنیم.
خوشحال می‌شوم اگر علاقه‌مند هستی، عضو گروه شوی و سوالاتت را مطرح کنی.


کتابخانه‌های مناسب برای امضای توکن

کتابخانه‌های زیادی در زبان‌های مختلف برای امضا و اعتبارسنجی JWT وجود دارد.
یک فهرست کامل و خوب از این کتابخانه‌ها را می‌توانی در سایت رسمی jwt.io/libraries ببینی.


راه‌های ارتباطی

اگر دوست داشتی برای من بنویسی یا حرفی بزنی، از طریق شبکه‌های اجتماعی مثل توییتر و اینستاگرام در دسترسم بصورت کامنت و ریپلای ها.
اگر هم نکته‌ای را از قلم انداخته‌ام یا دلت می‌خواهد در مورد موضوع خاصی بیشتر بنویسم، خوشحال می‌شوم در گروه تلگرام گفت‌وگو کنیم. من از هر ایده‌ای که منجر به تبادل علم و افزایش دانش شود، شدیداً استقبال می‌کنم.

و یادت نره: کد بزن! 🚀