پیاده سازی احراز هویت JWT در API وب
احراز هویت
قبل از به وجود آمدن JSON Web Tocken ها تسلط بر احراز هویت سمت سرور بسیار حائز اهمیت بود. به دلیل State Less بودن پروتکل HTTP در هر درخواستی که سمت سرور ارسال می شود، کاربر باید خود را معرفی کند. مثلا می بایست هر سری نام کاربری و کلمه عبور خود را ارسال کند تا معرف مشخصات و اعتبار وی باشد. این کار به شدت امنیت را زیر سوال می برد چرا که کلاینت داده های کاربر را پیش خود ذخیره می کند و داده های اصلی را بصورت خام ارسال می کند.
ساختار JWT
JWT در مقابل Session
زمان ورود به سیستم در سیستم هایی که از Session استفاده می کنند، کاربر پس از دریافت اطلاعات کاربر (نام کاربری و رمز عبور) یک شناسه به سرور تحویل می دهد. این شناسه سمت سرور در یک جدول از پایگاه داده یا روی یک فایل ذخیره خواهد شد (البته می توان در سرویس های دیگری مثل Redis نیز آنها را ذخیره کرد که از این مقوله خار است).
دلیل استفاده از JWT
- یک لایه امنیتی بیشتر
- سادگی خطایابی
- مقیاس پذیر بودن
- دارای عملکرد انقضای داخلی
- مناسب برای RESTful API
- امکان جدا سازی سیستم احراز هویت (میکرو سرویس) از نرم افزار اصلی
- خودمختاری JWT
مقیاس پذیر بودن JWT
داده های SESSION در یک ظرف (جدول پایگاه داده، فایل، سرور REDIS و…) ذخیره می شوند. پس در صورت رشد سیستم داده های مورد نظر هم بزرگ می شوند. از آنجا که محل ذخیره سازی جایی است که برای هر عملکردی (حد اقل برای هر درخواست مسیریابی) باید به آن رجوع شود باید بتوانیم آن را بین سرور های مختلف بشکنیم و بتوانیم سیستم احراز هویت را جدای از سیستم مورد نظر استفاده کنیم. با JWT این امر ممکن می شود.
یک لایه امنیتی بیشتر با JWT
هدف اصلی JWT عدم مداخله کاربر (سمت کلاینت) است. البته بهتر است که رمزگذاری شوند تا امنیت آنها بیشتر شود. JWT باید حتما جایی ذخیره شوند تا سری بعد ارسال شوند، از این رو مکان ذخیره سازی می تواند کوکی مرورگر کاربر باشد. ذخیره سازی JWT می تواند سیستم احراز هویت را در برابر حملات XSS (Cross-site Scripting) آسیب پذیر کند. یعنی یک تکه کد جاوا اسکریپت در وبسایت شما تزریق می شود و این کد اقدام به خواندن JWT از کوکی مرورگر کاربر می کند و پس از آن اقدام به حمله CSRF – Cross-site Request Forgery = جعل درخواست میان وبسایتی می کند. پس درخواستها از وبسایت دیگر به وبسایت اصلی اجرا می شود.
استفاده از تکنیک های مناسب امنیتی به هدف توسعه دهنده سیستم بستگی دارد اما از راه های مناسب برای جلوگیری از این حملات میتوان به موارد زیر اشاره کرد.
- تعریف تاریخ انقضا برای JWT ها
- تنها درخواستها از سمت دامنه ای خاص پاسخ داده شوند
- اختصاص JWT ها به آدرس های IP مشخص
- استفاده از اثر انگشت مرورگر (Browser Fingerprint)
استفاده از HTTPS / SSL / TLS جهت جلوگیری از خوانده شدن JWT ها در بستر انتقالی (بین کلاینت و سرور) به امنیت وبسایت (سیستم احراز هویت شما) شما کمک می کند.
چگونه JWT ایجاد کنیم؟
JWT از سه قسمت تشکیل شده است که هر قسمت توسط یک . (نقطه) از بقیه جدا شده است. مانند روبرو:
xxxxx.yyyyy.zzzzz
به ترتیب فسمت های بالا را نامگذاری کرده اند:
- xxxxx – Header
- yyyyy – Payload
- zzzzz – Signature
پس برای ساخت یک JWT باید مراحل زیر را طی نمایید.
مرحله ۱ – ساخت HEADER :
{
"typ": "JWT",
"alg": "HS256"
}
مرحله 2 – ساخت PAYLOAD :
Payload داده هایی است که میخواهیم سمت سرور ارسال کنیم. به هر فیلدی از داده که ارسال می کنیم یک Claim گفته می شود.
{
"userId": "b08f86af-35da-48f2-8fab-cef3904660bd"
}
در مثال بالا تنها userId ارسال می شود. اگر نرم افزار ویدئوکنفرانس در قسمت دیگر باشد می توان نام جلسه را نیز ارسال کرد یا این که زمان انقضای JWT را هم ارسال نمود.
مرحله 3 – ساخت SIGNATURE (امضاء):
// signature algorithm
data = base64urlEncode( header ) + “.” + base64urlEncode( payload )
hashedData = hash( data, secret )
signature = base64urlEncode( hashedData )
// header
eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9
// payload
eyJ1c2VySWQiOiJiMDhmODZhZi0zNWRhLTQ4ZjItOGZhYi1jZWYzOTA0NjYwYmQifQ
مرحله 4 – هر ۳ کامپوننت JWT ترکیب کنید:
چگونه JWT مراقب داده های ما است
// signature
-xN_h82PHVTCMA9vdoHrcZxH-x5mb11y1537t3rGzcM
مرحله 5 – تایید JWT
// JWT Token
eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VySWQiOiJiMDhmODZhZi0zNWRhLTQ4ZjItOGZhYi1jZWYzOTA0NjYwYmQifQ.-xN_h82PHVTCMA9vdoHrcZxH-x5mb11y1537t3rGzcM
چه فرقی بین احراز هویت توسط JWT با احراز هویت توسط session وجود دارد؟
Session اطلاعات کاربر را بصورت کوکی (Cooke) ذخیره می کند.
پس از اولین اعتبار
در اولین اعتبار کاربر احراز هویت می شود و پس از اولین اعتبار کاربر باید برای هر درخواست JWT را همراه درخواست خود ارسال کند.
مثلا لاراول بدین شکل عمل می کند و Web Token JSON را از با پیشوند Bearer ارسال می کند.
Authorization: Bearer
استفاده در زبان های مختلف
لطفا فکر نکنید که خود شما باید این موارد را بصورت Native برای زبان برنامه نویسی خود بنویسید. از قبل توسط برنامه نویسان مختلف و زیر نظر وبسایت JWT ماژول هایی تهییه شده که برای زبان ها و فریمورک های مختلف می توانید به وبسایت رسمی JWT مراجعه کنید.