Misaghlb

بلاگ من

JSON Web Tokens در مقابل Session Cookies

JSON Web Token ‏( JWT ) یک استاندارد باز ‏(RFC 7519) است که یک روش فشرده ‏(compact) و مستقل ‏(self-contained) برای انتقال امن اطلاعات بصورت آبجکت JSON تعریف میکند.
به دلیل امضای دیجیتالی که انجام میشود میتوان از صحت این اطلاعات اطمینان حاصل کرد.
امضای JWT ها توسط یک رمز (با الگوریتم HMAC) یا یک جفت کلید عمومی/خصوصی توسط RSA صورت میگیرد.

ساختار JWT

JWT ها اساساً شامل سه بخش هستند که توسط نقطه . از هم جدا میشوند.
که عبارتند از : header ، payload ، signature
برای توضیحات کامل درباره ساختار JWT به این مقاله مراجعه کنید.

JWT ها چگونه کار میکنند

در احراز هویت ‏(authentication)، وقتی که کاربر با موفقیت توسط یوزرنیم و پسوردش لاگین میکند،
یک JWT ‏( JSON Web Token) برگشت داده خواهد شد که در عوض روش سنتی ساخت سشن در سرور و برگشت دادن کوکی باید بصورت لوکال در سمت کاربر ذخیره بشود ( معمولاً در حافظه در کوکی هم می‌شود ذخیره کرد ).

هنگامی که کاربر بخواهد به یه مسیر محافظت شده دسترسی پیدا کند باید JWT را در هدر Authorization با اسکیمای Bearer ارسال کند.
هدر باید به این‌گونه باشد‌:

Authorization: Bearer<token>

به این مکانیزم احراز هویت stateless میگویند زیرا وضعیت کاربر هرگز در مموری سرور دخیره نمیشود.
مسیرهای محافظت شده سرور چک میکنند که اگر توکن معتبری در هدر Authorization وجود داشته باشد اجازه دسترسی به کاربر داده میشود. به دلیل اینکه JWT ها مستقل (self-contained) هستند تمام اطلاعات ضروری را در خودش دارد و بار اضافی ارتباط با دیتابیس رو کاهش میدهند.

جریان کاری احراز هویت :

authentication workflow

چرا از JWT ها استفاده کنیم ؟

دلایل زیادی وجود دارد :

  • آسانی scale horizontally ( گسترش برنامه بر روي چند سرور مي باشد)
  • آسانی نگهداری و دیباگ
  • قابلیت ساختن سرویس های RESTful واقعی
  • قابلیت توکار منقضی شدن
  • مستقل بودن (خود شمول) (self-contained)

در ادامه توضیحات کاملی درباره موارد بالا داده میشود.

JWTs در مقابل Sessions

قبل از JSON Web Tokens ها، باید از احراز هویت سرور محور(server-base) استفاده میکردیم.
همونطور که همه میدونیم، پروتکل Stateless HTTP هست، به این معنی که اگر یک یوزر با username و password احراز هویت بشود، سپس در طی درخواست (Request) بعدی اپلیکشن یوزر را نمیشناسد و باید دوباره احراز هویت بشود.
پس این نیاز به وجود اومد تا مطمین شد که وقتی یوزری لاگین میکند وضعیت احراز هویت کاربر بتونه در درخواست های بعدی نیز معتبر باشد.

session workflow

اطلاعت کاربر ( username password … ) بصورت درخواست POST به سرور ارسال میشودو سرور کاربر را احراز هویت میکند. اگر این اطلاعات صحیح باشند سرور با یک کوکی که در مرورگر کاربر ذخیره می‌شود و شامل یک SESSION ID است برای شناسایی کاربر استفاده می‌شود، پاسخ میدهد.
سشن های کاربر در مموری یا در فایل و یا در دیتابیس سرور ذخیره میشوند.

حالا میخاهیم در موارد زیر JWT هارو با Sessions مقایسه کنیم‌:

1. Scalability

هنگامی که برنامه شما رشد پیدا میکنه و تعداد کاربر ها زیاد میشن شما یاید شروع به scale کردن چه بصورت افقی و یا عمودی کنید.
داده‌ های سشن در مموری یا فایل یا دیتابیس سرور ذخیره می‌شوند. در سناریوی horizontal scaling که به افزایش تعداد سرورها (replicating) می‌انجامد شما باید یک محل ذخیره سازیه سشن مرکزی را تهیه کنید که همه اپلیکشن ها بتوانند به آن دسترسی داشته باشند. در غیراینصورت نخواهید توانست اپلیکشن خود را گسترش بدهید.
راه دیگری که بتوانید این مشکل رو برطرف کنید این است که از مفهوم sticky sessions استفاده کنید.شما میتونید سشن هایتان را روی دیسک ذخیره کنید تا بنوانید راحت‌تر اپلیکشنتان را در کلود گسترش دهید. ولی این راه‌ها دیگر برای اپلیکشن ها مدرن و بزرگ امروزی کارساز نیستند.
در‌واقع راه انداری این‌گونه سیستم‌های توزیع شده و نگهداری آن‌ها هم دانش فنی زیادی نیاز دارد و هم اینکه باعث افزایش هزینه‌ها میشود.
در این مورد، استفاده از JWT کار را راحت‌ میکند.دیگر نیازی به ذخیره اطلاعات کاربر در سشن نیست زیرا احراز هویت توکن-محور stateless هست.
اپلیکشن ما به راحتی میتواند گسترش پیدا بکند زیرا میتونیم از توکن ها برای دسترسی به منابع از سرورهای مختلف استغاده کنیم بدون اینکه نگران باشیم که یوزر واقعاً در یک سرور لاگین کرده است.
همچنین باعث کاهش هزینه‌ها نیز می‌شود چون دیگر نیازی به تهیه سرور اختصاصی برای دخیره سشن ها نیست.چرا؟ چون دیگر سشنی وجود ندارد!

نکته: اگر شما اپلیکشنی میسازید که کوچک است و نیازی به گسترش و scale up ندارد تا روی چندین سرور اجرا شود و همچنین نیازی به RESTful Api ها ندارید قطعاً سشن ها برای شما مناسب است.
اگر میتونید از سرور اختصاصی برای اجرای ابزاری مثل Redis برای ذخیزه سازی سشن ها استفاده کنید آن موقع احتمالاً سشن ها بتوانند به خوبی کار کنند.

۲. Security

امنیت: امضا کردن JWT ها باعث جلوگیری از دستکاری آن‌ها در سمت کلاینت می‌شود ولی همچنان میتوانند encrypt شوند تا مطمین شویم که claim هایی که در توکن هستند بسیار امن میباشند. توکن ها اغلب بصورت مستقیم در web storage (لوکال / سشن) یا در کوکی ها ذخیره میشوند.
وجاوا اسکریپت به این فضا دسترسی دارد و این به معنی این است ممکنه توکن ها توسط حملات XSS ‏(Cross-site Scripting)‏ در خطر قرار گیرند. بدافزارهای جاوااسکریپ میتوانند در صفحات مخفی شوند و با باز کردن آن صفحات به فضای ذخیره سازی توکن ها دسترسی داشته باشند. بسیاری معتقند که به دلیل حملات XSS همچنین اطلاعات حساسی نباید در web storage ذخیره شوند.

در ابتدا اشاره کردم که JWT ها میتوانند در کوکی ها ذخیره شوند. در‌واقع توکن ها در بسیاری از کوارد بعنوان کوکی ذخیره می‌شوند و کوکی ها نیز در خطر حملات CSRF ‏(Cross-site Request Forgery)‏ هستند. یکی از راه‌های زیادی که می‌شود از این حملات جلوگیری کرد این است که کوکی تنها از دامین شما در دسترس است. بعنوان یک توسعه‌دهنده حواستان جمع باشد که وقتی از توکن ها استفاده میکنید این مورد رو درنظر بگیرید و از راهکار مناسب استفاده کنید.

سشن ها و توکن ها همچنین در معرض خطر حملات replay نیز هستند. این کاملاً برعهده توسعه‌دهنده است که از چه تکنیک و راهکاری متناسب با سیستم برای کاهش و جلوگیری از این حملات استفاده کند.
یکی از راه‌هایی که میتوان این مشکل را حل کرد این است برای توکن زمان انقضا کوتاه در نظر گرفته شود. اگرچه این تکنیک کاملاً مشکل را حل نمیکند.همچینین راه‌های دیگر برای مقابله با این چالش تولید توکن برای ip های مشخص است و همچنین استفاده از browser fingerprinting.

نکته: از HTTPS/SSL استفاده کنید تا مطمین شوید که کوکی ها و سشن ها در طول انتقال بین کلاینت و سرور encrypte شده‌اند. این کمک میکنه که از حمله های مرد میانی ‏(man-in-the-middle)‏ جلوگیری شود.

ادامه دارد …