לדלג לתוכן

מה זה Mass Assignment, ואיך שדה אחד נוסף הופך אתכם למנהלי מערכת

תארו לעצמכם שאתם נרשמים לאתר, ממלאים טופס עם שם ואימייל וסיסמה, ובלי לשים לב, מוסיפים לבקשה שדה אחד קטן נוסף - "role": "admin". עכשיו תארו שהשרת פשוט מקבל את זה. בלי בדיקה, בלי שאלה, בלי שום דבר. זה בדיוק מה ש-Mass Assignment הוא, וזו אחת מהחולשות ההגיוניות ביותר להבין ברגע שרואים אותה בפעולה בפעם הראשונה.

אז מה קורה בפועל

הרבה פריימוורקים מודרניים, בין אם זה ORM שמתקשר עם מסד נתונים או פריימוורק שמטפל בבקשות API, מציעים תכונה נוחה מאוד למפתחים - קישור אוטומטי. אתם שולחים אובייקט JSON, והפריימוורק לוקח את כל השדות בו, ו"ממפה" אותם ישירות לתכונות של אובייקט פנימי במערכת - בלי שהמפתח צריך לכתוב ידנית שורה שממפה כל שדה בנפרד.

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

דוגמה שמבהירה את זה

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

אבל אם השרת פשוט לוקח את כל גוף הבקשה וממפה אותו לאובייקט המשתמש בלי הגבלה, שום דבר לא עוצר תוקף מלשלוח בקשה שכוללת גם "role": "admin" או "isVerified": true, גם אם הטופס בעצמו לא מציג שדות כאלה. הקלט הזה פשוט לא מגיע דרך הטופס - הוא מגיע ישירות בבקשת ה-HTTP, ואם אין בדיקה בצד השרת, הפריימוורק "יעזור" לתוקף לשמור את זה בדיוק כמו כל שדה לגיטימי אחר.

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

למה זה כל כך נפוץ

הבעיה נובעת מתפיסת עולם שנקראת "convention over configuration" - פריימוורקים רבים בנויים כך שברירת המחדל היא נוחות מקסימלית, ולא אבטחה מקסימלית. ORM-ים שממפים בקשות ישירות למודלים במסד הנתונים, ופריימוורקים של API שממירים JSON לאובייקטים אוטומטית, שניהם נבנו כדי לחסוך זמן פיתוח - וזה עובד מצוין, עד שמישהו שוכח להגביל אילו שדות מותר לקבל מבחוץ.

זו לא בעיה של שפה או טכנולוגיה ספציפית. זו קיימת בכל סביבה שבה הנוחות של "תמפה לי הכל אוטומטית" מנצחת את המשמעת של "תגדיר לי בדיוק מה מותר".

איך מונעים את זה

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

זיהוי חולשות Mass Assignment דורש חשיבה קצת אחרת מסריקת קוד רגילה - צריך להשוות בין מה שממשק המשתמש מציג, לבין מה שה-API בפועל מוכן לקבל, ולבדוק בעצמכם אילו שדות "נשכחו" בלי הגבלה. זה בדיוק סוג הפער שאנחנו מתרגלים למצוא בקורס פריצת אתרים מתקדם, כי חולשות מהסוג הזה כמעט אף פעם לא בולטות לעין - צריך לדעת בדיוק איפה לחפש.

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

הצטרפו לקהילה בדיסקורד

לסיכום

Mass Assignment היא תזכורת לכך שנוחות ואבטחה לא תמיד הולכות יחד. פריימוורק שממפה הכל אוטומטית חוסך למפתחים זמן, אבל בלי allowlist מפורש, כל שדה נוסף שמישהו מוסיף לבקשה עלול להתקבל בברכה - כולל השדה שהופך אתכם למנהלי המערכת.