אחרי שאתם מתחברים לשירות אינטרנטי, השרת נותן לדפדפן פתק חתום שאומר מי אתם, וכל בקשה נוספת נבדקת מולו. python-jose היא ספרייה נפוצה שמייצרת ופותחת פתקים כאלה בשירותים שכתובים בפייתון. החולשה הזאת מאפשרת למי שמחזיק במפתח הציבורי של השירות, מידע שאינו סוד, לייצר פתק מזויף שעובר את הבדיקה. הציון שנקבע לה הוא 9.3 מתוך 10, והיא נמצאת בכל הגרסאות עד 3.5.0 ועד בכלל.

מה החולשה?

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

הבעיה מתחילה כשספרייה מוכנה לקבל את המפתח הציבורי כחומר גלם לחתימה מהסוג השני. python-jose אמורה לפסול מפתח אסימטרי בשלב שבו היא מאתחלת חתימת HMAC, וכאן הבדיקה הזאת מפספסת: מפתח ציבורי שמקודד בצורת DER, בלי מעטפת ה-PEM ובלי התחיליות של SSH, עובר אותה. התוקף לוקח את המפתח הציבורי שהשירות מפרסם ממילא, מייצר token חתום ב-HS256 שמשתמש בו כסוד המשותף, והשרת שמאמת חוזר על אותו חישוב ומקבל התאמה.

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

הרשומה מציינת עוד דבר שכדאי להכיר: זהו תיקון חלקי לחולשה קודמת באותה ספרייה, CVE-2024-33663. כלומר הבעיה הזאת כבר טופלה פעם אחת, והדרך לעקוף את התיקון נשארה פתוחה.

מי מושפע?

שירותים ואתרים שכתובים בפייתון ומשתמשים ב-python-jose בגרסה 3.5.0 או מוקדמת ממנה כדי לאמת token-ים. זה לא מוצר שמשתמש קצה מתקין, אלא רכיב שיושב בתוך מערכות: ממשקי API, אזורים אישיים באתרים, מערכות פנימיות בארגונים. בישראל מדובר בעיקר בצוותי פיתוח, ובכל מי שהמערכת שלו נבנתה בפייתון והאימות בה נשען על הספרייה הזאת.

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

האם מנוצלת בפועל?

החולשה אינה מופיעה בקטלוג ה-KEV של סוכנות הסייבר האמריקאית CISA, הקטלוג שמרכז חולשות שיש עדות לניצולן בשטח, נכון לעדכון האחרון של הדף. שווה לזכור שחולשה בספריית אימות אינה מייצרת רעש: token מזויף שעובר בדיקה נראה בצד השרת כמו כניסה תקינה לגמרי.

מה עושים?

בדקו קודם אם הספרייה בכלל אצלכם. בסביבה של הפרויקט הריצו pip show python-jose, או חפשו את שמה בקובץ הדרישות. אם היא שם, הגרסה שמוצגת היא מה שקובע.

התיקון המעשי המהיר ביותר הוא להגביל את האלגוריתמים בקריאה לאימות. בכל מקום שבו הקוד קורא ל-jwt.decode, העבירו במפורש את רשימת האלגוריתמים המותרים, למשל algorithms=["RS256"], ולא רשימה שכוללת את הצד הסימטרי. זה חוסם את הזיוף גם לפני שהספרייה מתעדכנת.

במקביל, בדקו בהתראה הרשמית של הספרייה אם כבר יצאה גרסה עם התיקון, ואם כן עדכנו אליה. הרשומה כאן מציינת שהחולשה קיימת בכל הגרסאות עד 3.5.0, בלי לנקוב בגרסה מתוקנת, ולכן ההתראה היא המקום לבדוק בו את המצב העדכני.

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