האם אי פעם חשבתם למה אנחנו צריכים לספק שם משתמש וסיסמא, כשאנחנו נרשמים (register) או מבצעים כניסה (login) לאתרים כמו Facebook, Twitter וכדומה? הפעולה הזו של ההזדהות, נותנת למערכות לאפשר לנו לבצע פעולות במערכת שלהם, כמו לפרסם פוסט, להגיב על פוסט וכדומה.
אבל האם אי פעם חשבתם מה קורה מאחורי הקלעים כשאנחנו מבצעים פעולה כזו של הזדהות? או מבצעים פעולה מסוימת כמו פרסום פוסט וכדומה? במאמר הזה, אנחנו נדבר על שלושה דברים חשובים שכל אתר חייב להטמיע אם הוא מאפשר למשתמשים שלו להירשם ולבצע פעולות בחשבון, והם:
אימות (Authentication)
הרשאה (Authorization)
JWT (JSON Web Token)
אימות (Authentication)
אימות הוא תהליך שבו מערכת בודקת את זהותו של משתמש (user) באמצעות מגוון דרכים כמו כתובת דוא"ל, שם משתמש, וסיסמא. כשאנחנו נרשמים או מתחברים לאתרים כמו Facebook או Twitter, אנחנו מקבלים גישה לפעולות שלא היינו יכולים לקבל אם לא היינו מבצעים תהליך של אימות, כמו פרסום פוסט או תגובה לדוגמה.
כלומר שאנחנו עוברים תהליך של אימות, אנחנו בתוך המערכת, ולכן יש לנו גישה לפעולות מסוימות. תהליך האימות מאפשר לאתר (למערכת) לשמור על בטחון המשתמשים בכך שלא כל אחד יכול לקבל גישה לפעולות מסוימות, אלא רק למשתמשים (users) שביצעו אימות.
הרשאה (Authorization)
הרשאה היא התהליך שבו מערכת קובעת אילו משאבים או פעולות משתמש מורשה לגשת אליהם או לבצע לאחר שהוא עבר את תהליך האימות. במילים אחרות, לאחר שהמערכת מזהה את המשתמש (למשל, על ידי שם משתמש וסיסמה), היא צריכה להחליט מה הוא מורשה לעשות במערכת.
לדוגמה, באתר כמו Facebook, משתמש שעבר אימות יכול לפרסם פוסטים תחת שמו או למחוק פוסטים תחת שמו, אך אין לו הרשאה למחוק פוסטים של משתמשים אחרים. כלומר ההרשאה מבטיחה שלכל משתמש (user) במערכת, יש גבולות ברורים לפעולות שהוא יכול לבצע, ובכך מגנה על המערכת מפני שימוש לא ראוי או התערבות בפרטיות ובזכויות של משתמשים אחרים.
JWT (JSON Web Token)
בחלק הזה, אנחנו נלמד איך JWT (JSON Web Token) עובד וממה הוא מורכב, וגם חסרונות ויתרונות כדי שיהיה לכם את כל המידע הרלוונטי והשלם.
איך JWT עובד?
כשאנחנו מתחברים למערכת לאחר פעולות כמו login או register, מונפק לנו משהו שנקרא JWT. תחשבו על JWT כאל כרטיס זיהוי במערכת שמזהה אתכם בכל פעם שאתם רוצים לבצע פעולה מסוימת או לקבל גישה למשהו מסוים, והוא בודק האם יש לכם הרשאה או לא.
כל פעם שאתם מגיבים למשתמש בFacebook או מעלים פוסט וכדומה, אתם שולחים בקשה לשרת ביחד עם ה-JWT שהונפק לכם בשעת האימות, ולמה ביחד עם ה-JWT? כי השרת משתמש ב-JWT שהונפק לכם כדי לוודא שאתם משתמשים אמתיים, וכדי לקרוא אלו הרשאות יש לכם, ואם יש לכם את ההרשאה המתאימה, אתם תוכלו לבצע את אותה פעולה. אם האימות נכשל מסיבה כזו או אחרת, המשתמש לא יוכל לבצע שום פעולה באתר, וברוב הפעמים, ייצא מן המערכת בצורה programmatically.
JWT מורכב משלושה חלקים:
JWT מורכב משלושה חלקים, שכל אחד מהם מופרד על ידי נקודה (.).
Header - מכיל מידע על הסוג של האלגוריתם ששימש להצפנת ה-JWT.
Payload - מאחסן את פרטי המשתמש, כגון כתובת אימייל, שם משתמש ועוד. חשוב לזכור שלמרות שה-JWT מאובטח, לא נהוג לשמור בו מידע רגיש כמו סיסמאות או פרטי כרטיסי אשראי. המטרה של ה-payload היא לאחסן מידע שנחוץ לאימות ולבדיקת הרשאות בלבד.
Signature - תפקידה לאשר את אותנטיות של ה-JWT. החתימה מבטיחה שה-JWT נותר נאמן למקור שיצר אותו ולא עבר שינויים לא מורשים לאחר שהונפק.
אחסון ה-JWT
שימו לב שמתכנתים צעירים שומרים את אותו JWT ב-local storage וזה נחשב security issue כי local storage מיועד להתקפה של XSS (Cross-Site Scripting). במקום זאת עדיף לשמור אותו ב-HttpOnly cookie כי לא ניתן לגשת לשם באמצעות JavaScript ו-HttpOnly cookie חסין מפני התקפות XSS.
יתרונות השימוש ב-JWT:
אחד היתרונות העיקריים של השימוש ב-JWT זה שהוא קטן וקומפקטי, וקל להעביר אותו בין צד לקוח לשרת. יתרון שני הוא הפופולריות שלו. הרבה מאוד ארגונים קטנים וגדולים משתמשים בו על מנת לחזק ולאבטח את האתרים שלהם. כמובן שיש עוד יתרונות, אבל אנחנו נתמקד בחשובות והבסיסיות.
חסרונות השימוש ב-JWT:
אחד החסרונות העיקריים של השימוש ב-JWT הוא שה-payload אינו מוצפן כברירת מחדל. המשמעות היא שכל מי שמיירט את ה-JWT יכול לקרוא את המידע הכלול. כדי להפחית סיכון זה, ניתן להצפין JWT באמצעות זוג מפתחות ציבורי/פרטי.
יישום JWT (JSON Web Token) באפליקציית Node.js :
יצירת ה-JWT:
עם הקוד שכתבנו למעלה, אנחנו יוצרים JWT באמצעות ספריית jsonwebtoken. הפונקציה מקבלת אובייקט עם המאפיינים _id, firstName, lastName, email ו-isAdmin, והאובייקט הזה יהיה ה-payload של אותו JWT. כשאנחנו יוצרים את ה-JWT, אנחנו מאבטחים אותו עם secretOrPrivateKey שרק אתו אנחנו נייצר JWT.
בגלל שה-secretOrPrivateKey צריך להיות פרטי ולא חשוף לעולם החיצוני, אנחנו ניישם אותו תחת משתנה סביבתי (Environment variable), מה שמבטיח שה-JWT יהיה תקף, רק אם המפתח הסודי (secretOrPrivateKey) תואם. בנוסף, אנחנו מגדירים את ה-JWT לפוג לאחר שלושה ימים, כפי שצוין במאפיין expiresIn.
שימוש בפונקציה של יצירת ה-JWT:
בקוד שכתבנו למעלה, תוכלו לראות שבנינו route פשוט שאחראי ל-signIn. אנחנו לוקחים את נתוני המשתמש כמו שם, כתובת אימייל וכדומה, ושולחים את האובייקט "propsForToken" לפונקציה שראיתם למעלה "generateUserToken". אנחנו משתמשים ב-httpOnly cookie כדי לאחסן את ה-JWT שלנו בצורה מאובטחת.
בדיקת הרשאות:
בקוד למעלה, ,תוכל לראות שיש route שאמור לעדכן את פרטי המשתמש, אבל כמובן לא כל אחד יכול, אלא רק למי שיש את ההרשאות המתאימות יכול לעדכן את פרטי המשתמש, לדוגמה המשתמש עצמו והמנהל. שימו לב שבאמצע של ה-route אנחנו משתמשים ב-middleware שמספקת לנו שכבת הגנה לפני שאנחנו מגיעים ל-route's method עצמה.
בעצם בתוך ה-middleware אנחנו מוודאים שהכל תקין, כלומר שיש למשתמש שלנו JWT אמיתי, ואם הוא אמיתי, הוא יוכל לבצע את הפעולה שהוא רצה (עדכון פרטי המשתמש).