JWT: המלכודות הנפוצות שהופכות טוקן נוח לפרצת אבטחה

מאת צוות מדיה דיל · 31.08.2026 · אבטחת מידע · 7 דק׳ קריאה

JWT הפך לסטנדרט כמעט ברירת מחדל לאימות, אבל שימוש לא זהיר בו יוצר פרצות אבטחה קלאסיות. הנה המלכודות שחייבים להכיר.

JWT (JSON Web Token) הוא אסימון חתום שמכיל מידע על המשתמש, ומאפשר לשרת לאמת בקשה בלי לפנות למסד נתונים בכל פעם — פשוט לבדוק את החתימה. הנוחות הזו הפכה אותו לסטנדרט נפוץ מאוד, אבל כמה מלכודות קלאסיות הופכות אותו למסוכן כשלא מטפלים בו נכון.

מלכודת alg: none — קבלת טוקן לא חתום

תקן JWT מאפשר, תיאורטית, אלגוריתם "none" שמשמעו טוקן ללא חתימה כלל. ספריות ישנות או מוגדרות לא נכון עלולות לקבל טוקן כזה כתקף — מה שמאפשר לתוקף ליצור טוקן מזויף לחלוטין. הגנה: לאכוף במפורש רק את האלגוריתם הצפוי, ולא לתת לטוקן "לבחור" את שיטת האימות שלו.

בלבול בין HS256 ל-RS256

אם שרת מוגדר לקבל גם מפתח סימטרי (HS256) וגם אסימטרי (RS256), תוקף שמכיר את המפתח הציבורי (RS256, שמיועד להיות ציבורי) יכול לנסות להשתמש בו כמפתח סימטרי לחתום טוקן מזויף. הגנה: לאכוף אלגוריתם יחיד וקבוע מראש, לא לתת לכותרת הטוקן לקבוע אותו.

בעיית הביטול: JWT שלא ניתן לבטל

מכיוון ש-JWT מאומת ללא פנייה למסד נתונים, אין דרך פשוטה "לבטל" אותו לפני שהוא פג תוקף — גם אם המשתמש התנתק או החשבון נחסם, הטוקן עדיין תקף עד לתפוגתו. הפתרון הנפוץ: תוקף קצר (דקות) לטוקן עצמו, בשילוב Refresh Token שכן ניתן לבטל במסד נתונים.

אחסון לא בטוח בצד הלקוח

שמירת JWT ב-localStorage חושפת אותו לגניבה דרך XSS — כל סקריפט זדוני שרץ בדף יכול לקרוא אותו. Cookie עם דגלים HttpOnly ו-Secure מגן טוב יותר, כי JavaScript בצד הלקוח כלל לא יכול לגשת אליו, גם אם יש פרצת XSS.

תוקף ארוך מדי

טוקן עם תוקף של ימים או שבועות מגדיל דרמטית את חלון הפגיעות אם הוא נגנב. תוקף קצר (דקות עד שעה) עם רענון תדיר באמצעות Refresh Token מצמצם את הנזק הפוטנציאלי, גם אם הוא דורש מעט יותר לוגיקת רענון בצד הלקוח.

אי-בדיקת Claims קריטיים

טוקן תקף מבחינת חתימה עדיין צריך אימות נוסף — תאריך תפוגה (exp), יעד מיועד (aud), ומנפיק (iss). קבלת טוקן חתום כתקף בלי לבדוק את השדות האלה עלולה לאפשר שימוש בטוקן שהונפק להקשר אחר לגמרי.

JWT מול Session מסורתי

JWT לא תמיד הבחירה הנכונה — Session מסורתי עם מזהה במסד נתונים מאפשר ביטול מיידי ופשוט, במחיר של פנייה למסד נתונים בכל בקשה. הבחירה תלויה בקנה המידה ובדרישות: אפליקציות שדורשות ביטול מיידי (בנקאות, ניהול משתמשים רגיש) לרוב מעדיפות Session על פני JWT טהור.

גודל הטוקן ועומס על כל בקשה

מכיוון ש-JWT נשלח בכל בקשה בכותרת, טוקן שמכיל יותר מדי מידע (Claims מיותרים, הרשאות מפורטות מדי) מגדיל את משקל כל בקשה ובקשה. שמירה על טוקן מינימלי — רק מה שבאמת נדרש לאימות — משפרת ביצועים לצד השיפור באבטחה.

בדיקת חתימה לפני כל דבר אחר

ספריות JWT טובות מבצעות את אימות החתימה כשלב הראשון ההכרחי, לפני שקוראים בכלל את תוכן הטוקן. קוד שמפענח את תוכן הטוקן (decode) ובודק את החתימה בנפרד, בסדר הפוך, עלול בטעות להסתמך על מידע מטוקן שהחתימה שלו בכלל לא אומתה עדיין.

המערכת שלכם משתמשת ב-JWT ואתם רוצים לוודא שהיא מוגנת נכון? וואטסאפ.

Refresh Token Rotation: מניעת שימוש חוזר בטוקן גנוב

אם Refresh Token נגנב — למשל דרך מכשיר נגוע או פרצת רשת — תוקף יכול להשתמש בו שוב ושוב כדי להנפיק Access Token חדשים, כל עוד הוא בתוקף, גם בלי לדעת סיסמה או פרטי התחברות. ברוטציה (Rotation), כל שימוש ב-Refresh Token מנפיק Refresh Token חדש ומבטל מיידית את הישן. כך אם תוקף ולקוח לגיטימי מנסים בשלב מסוים להשתמש באותו Refresh Token הישן, אחד מהם ייכשל — וזה אות אזהרה ברור שמאפשר למערכת לזהות שימוש חוזר חשוד ולבטל את כל שרשרת הטוקנים באופן מיידי, לפני שהנזק מתרחב.

העברת זהות בין שירותים במערכת מבוססת Microservices

כשבקשה עוברת בין כמה שירותים פנימיים באותה מערכת, JWT נוח להעברת זהות המשתמש המקורי בלי שכל שירות בשרשרת יצטרך לפנות בנפרד לשירות האימות המרכזי ולבזבז זמן תגובה יקר. עם זאת, צריך להיזהר מ"Token Passthrough" עיוור — שירות פנימי שמעביר הלאה טוקן שהונפק להקשר אחר, בלי לוודא ש-Claim ה-audience (aud) אכן מתאים ליעד החדש, עלול לפתוח פרצת הרשאה בין שירותים. עיקרון נכון הוא שכל שירות מאמת מחדש שהטוקן שהתקבל אצלו אכן מיועד לו ספציפית, ולא מסתמך על כך שהוא "עבר" אימות אצל שירות קודם בשרשרת בלבד.

ניהול וסבב מפתחות חתימה (Key Rotation)

מפתח חתימה שדולף מאפשר לתוקף לזייף טוקנים לגמרי ולהתחזות לכל משתמש שהוא בוחר, ולכן החלפה תקופתית של מפתחות היא הגנה חשובה שמצמצמת את חלון הפגיעות אם מפתח כן דולף בעתיד. שדה kid (Key ID) בכותרת הטוקן מאפשר לשרת לדעת איזה מפתח מתוך כמה מפתחות פעילים במקביל לבדוק מולו — כך אפשר להנפיק טוקנים חדשים עם מפתח חדש, בזמן שטוקנים ישנים שעדיין בתוקף ממשיכים להיבדק מול המפתח הישן שהם נחתמו בו, עד שהם פגים באופן טבעי, בלי לכפות התנתקות מיידית של כל המשתמשים בכל סבב מפתח.

אחסון טוקנים באפליקציות מובייל: הבדל מהדפדפן

באפליקציית מובייל אין למעשה Cookie בהקשר הרגיל של דפדפן, ולכן ההגנה של HttpOnly Cookie שתוארה למעלה לא רלוונטית ישירות — האחסון הנפוץ הוא Keychain באיירון ו-Keystore באנדרואיד, מנגנוני אחסון מוצפנים ברמת מערכת ההפעלה שנועדו בדיוק למטרה הזו. עם זאת, טוקן ששמור בזיכרון האפליקציה בזמן ריצה עדיין חשוף אם המכשיר עצמו נפרץ (Root או Jailbreak), ולכן העקרונות של תוקף קצר ורוטציית Refresh Token רלוונטיים באותה מידה גם בסביבת מובייל, לא רק בדפדפן.

Logout מלא: מחיקת הטוקן בצד הלקוח לא תמיד מספיקה

לחיצה על "התנתק" שרק מוחקת את הטוקן מהאחסון המקומי בדפדפן או במכשיר יוצרת תחושת ביטחון מטעה — אם מישהו כבר העתיק את הטוקן לפני המחיקה (למשל דרך פרצת XSS או מכשיר משותף), הוא עדיין תקף ושמיש עד לתפוגתו הטבעית, בלי קשר לכפתור ההתנתקות שנלחץ. התנתקות אמיתית ואמינה דורשת רשימת חסימה (Blocklist) בצד השרת, או ביטול Refresh Token ספציפי במסד הנתונים, לא רק פעולה קוסמטית בצד הלקוח.

JWS מול JWE: חתימה מול הצפנה בפועל

רוב השימושים ב-JWT הם למעשה JWS (JSON Web Signature) — התוכן גלוי לקריאה, רק חתום. כשהתוכן עצמו כולל מידע רגיש שאסור שהלקוח או צד שלישי יראו בבירור, נדרש JWE (JSON Web Encryption) שגם מצפין את התוכן, לא רק חותם אותו. בפועל רוב האפליקציות לא זקוקות ל-JWE, כי הן פשוט לא שמות מידע רגיש בתוך הטוקן מלכתחילה — אבל כשיש הכרח לעשות זאת, בלבול בין השניים והנחה שחתימה שקולה להצפנה היא טעות אבטחה של ממש.

כן. אימות חתימת ה-JWT מוכיח שהזהות בטוקן אמיתית ולא זויפה, אבל לא בהכרח משקף הרשאות עדכניות — משתמש שהרשאותיו שונו אחרי הנפקת הטוקן עדיין מחזיק טוקן עם ההרשאות הישנות עד לתפוגתו. מערכות רגישות בודקות הרשאות קריטיות מול מקור עדכני, לא מסתמכות רק על מה שכתוב בטוקן שהונפק קודם.

שאלות נפוצות

האם התוכן בתוך JWT מוצפן?

לא, ברירת המחדל של JWT (חתימה בלבד, JWS) רק חותמת את התוכן ומוודאת שהוא לא שונה מאז ההנפקה — אך כל אחד יכול לפענח (decode) ולקרוא אותו, כי הוא רק מקודד ב-Base64 ולא מוצפן בפועל. מי שצריך גם להסתיר את התוכן מהלקוח עצמו זקוק לפורמט הצפנה נפרד (JWE) בנוסף לחתימה, ולא רק לחתימה בלבד.

כמה זמן תוקף מומלץ לתת ל-Access Token?

אין מספר אוניברסלי מדויק שמתאים לכל מערכת, אבל העיקרון הוא תוקף קצר ככל האפשר — דקות עד שעה בודדת ברוב המקרים — כדי לצמצם את הנזק אם הטוקן נגנב, בשילוב Refresh Token ארוך יותר שמאפשר חוויית משתמש רציפה בלי דרישת התחברות חוזרת תכופה מדי.

מה ההבדל המהותי בין JWT ל-Session Cookie מבחינת אבטחה?

Session מסורתי שומר את המצב במסד נתונים בצד השרת ומזהה אותו רק במזהה קצר אצל הלקוח, כך שביטול מיידי פשוט — פשוט מוחקים או מסמנים את הרשומה כלא תקפה. JWT שומר את המצב אצל הלקוח עצמו ומאומת בלי פנייה למסד נתונים בכל בקשה, מה שמהיר ומקל על קנה מידה, אך הופך ביטול מיידי למאתגר יותר, כפי שהוסבר למעלה.

האם אפשר לשנות את התוכן של טוקן אחרי שהוא הונפק?

לא בלי לפסול אותו לחלוטין. כל שינוי בתוכן הטוקן משנה גם את החתימה שלו, ושרת שבודק חתימה כראוי יזהה מיד שהטוקן שונה מהמקור ויידחה אותו לגמרי. זו בדיוק התכונה שהופכת JWT לאמין — לא ההסתרה של התוכן, אלא ההוכחה המתמטית שהוא לא שונה מאז שהונפק ונחתם.

למה Refresh Token צריך טיפול נפרד מ-Access Token?

Access Token נועד לשימוש תכוף מאוד ובעל תוקף קצר, בעוד Refresh Token נועד רק להנפקת Access Token חדשים ולכן צריך תוקף ארוך יותר, אך גם הגנה מחמירה יותר — אחסון בטוח יותר, ולעיתים אפשרות ביטול מפורשת במסד נתונים כמתואר בסעיף הרוטציה — בדיוק כי דליפה שלו מסוכנת ומשמעותית יותר מדליפת Access Token בודד.

תגיות: JWT · JSON Web Token · אבטחת אימות · Token Security

← חזרה לבלוג · צור קשר