כדי לסייע לסטודנטים שאני מלמד במקומות שונים ואיכשהו תמיד חסרים לי מאמרים שאני יכול לשלוח לסטודנטים המסבירים למי שלומד מדעי המחשב דברים בסיסיים באבטחת מידע ובעברית. יש לא מעט מאמרים (אשתדל לתת קישורים איפה שיש) עם הסברים אבל ההסברים מיועדים לאנשים שלומדים אבטחת מידע ומכילים כבר מונחים מהתחום שפחות רלוונטיים לאנשים שצריכים ללמוד את המבוא. אז כדי לעזור לעצמי, כתבתי סדרת מאמרים שמסבירים מונחים בסיסיים באבטחת מידע ובדגש על ווב ופיתוח ומה שמפתחים מתחילים צריכים לדעת. במאמר זה אני מסביר על התקפה מעניינת ונפוצה בשם Privilege Escalation.
איך הרשאות מנוהלות?
כדי להבין את ההתקפה הזו, אנו צריכים להבין איך אתרים ומערכות מנהלות הרשאות. זה כמובן נושא מאד מקיף אז אני אצטרך לכתוב באופן פשוט יחסית שלעתים חוטא לאמת ולמורכבות אבל מעביר את הרעיון. בגדול, כאשר מישהו מקבל תפקיד במערכת הוא מקבל role – תפקיד. לכל תפקיד יש הרשאות. למשל, אם נסתכל על וורדפרס. נראה שבמערכת וורדפרס קיימים חמישה תפקידים ראשיים עם הרשאות שונות:
- מנהל מערכת (Administrator): בעל גישה מלאה לניהול האתר, כולל שינוי הגדרות, התקנת תוספים, וניהול משתמשים.
- עורך (Editor): יכול לפרסם ולנהל פוסטים, כולל פוסטים של משתמשים אחרים.
- כותב (Author): יכול לכתוב, לערוך ולפרסם פוסטים אישיים.
- תורם (Contributor): יכול לכתוב ולערוך פוסטים אישיים אך לא לפרסמם.
- מנוי (Subscriber): יכול רק לנהל את הפרופיל האישי שלו ולהגיב על פוסטים.
לכל תפקיד יש את ההרשאות שלו. בוורדפרס לכל תפקיד יש את התפקידים שלו ושל אלו שנמוכים מהם בהיררכיה. כשאני מבצע כניסה למערכת, אני מקבל role מתאים. לעתים זה מספר מזהה, לפעמים – אם מדובר במערכת יותר פשוטה – יש שדה בוליאני (כלומר נכון/לא נכון) של isAdmin. אבל זו פרקטיקה גרועה.
Privilege Escalation אנכי
עד עכשיו זה נשמע סביר בהחלט, אבל בואו ונדמיין ,תרחיש מעניין – נניח שאני משתמש עם הרשאה מספר 5, של מנוי. אני יכול לנהל את הפרופיל האישי שלי וזהו. יש לי טופס שאני נכנס ויכול לעדכן שם משתמש, תמונה וכו׳ וכו׳. הטופס שולח אובייקט JSON (לא להבהל מהמבנה אם אתם לא מכירים) מהסוג הזה:
{
name: 'Whatever',
picture: '/wp-upload/whatever.jpg',
country: 'Israel'
}
מה קורה אם אני משתמש בטופס ושולח אותו, תחת השם שלי ועם טוקן ההרשאה שלי והכל אבל עם תוספת קטנה:
{
name: 'Whatever',
picture: '/wp-upload/whatever.jpg',
country: 'Israel',
role: 1
}
המערכת בודקת את הטופס – ראשית היא מוודאת את הזהות שלי ורואה שאני רשום במערכת וה-role שלי הוא מספר 5. כלומר אני יכול לשנות את הפרטים של עצמי. אחרי כן היא לוקחת את האובייקט ומשנה את המידע שלי לפי השדות – השם, התמונה, המדינה ו… סוג התפקיד. מהנקודה הזו אני עם תפקיד מסוג 1 – admin. הצלחתי להוציא לפועל מתקפה מסוג Privilege Escalation. היתה לי הרשאה, והצלחתי להקפיץ אותה – כלומר לעשות לה Escalation.
זו דוגמה ל Escalation אנכי. אני מתקדם בתפקיד באופן אנכי מתפקיד נמוך לתפקיד גבוה.
בואו ונדגים עם מערכת נוספת, קצת יותר פרימיטיבית. נניח ויש שתי רמות של משתמשים – משתמש אדמין ומשתמש רגיל. משתמש רגיל לא יכול לעשות פעולות מסוימות. כך נעשית בדיקה של התפקיד לדוגמה בקוד Node.js. לא צריך להכיר בכלל שפת תכנות בשביל להבין מה קורה פה – הדגשתי את החלק הרלוונטי:
app.get('/admin', (req, res) => {
if (req.user.role === 'admin') {
res.send('Welcome Admin');
} else {
res.status(403).send('Forbidden');
}
});
נעשית בדיקה של ה-role על כל בקשה של המשתמש. במקרה הזה יש בבקשה של המשתמש אובייקט (כלומר אוסף של נתונים) שנקרא user. מה יש שם? יש שם הגדרה של role והיא נבדקת – אם היא admin (=== שזה שווה) אז המשתמש הוא admin.
אבל מאיפה התפקיד הזה מגיע? ובכן, אם נעשית בדיקה במסד הנתונים על תפקיד המשתמש – זה מצוין. אבל לפעמים יש לנו מימוש כזה (אני אסביר מייד אחר כך מה זה, לא להבהל).
app.use((req, res, next) => {
if (req.headers['x-role']) {
req.user.role = req.headers['x-role']; // אוי א-ברוך
}
next();
});
הקוד הזה בודק מה שנקרא Headers שמגיע מהמשתמש ומכניס את ה-Header ששמו הוא x-role ל req.user.role. מה זה אומר? שהשרת מאכלס את הנתון req.user.role בהתאם למה שמגיע מהמשתמש. כל מה שמגיע מהמשתמש ניתן לזיוף וכאן זה קל ממש לזיוף 😱 ותאמינו או לא, זה קוד אמיתי. כמו גם לפעמים עוגיה שיש בה isAdmin שהוא true\false – כל מה שהמשתמש צריך לעשות זה לשנות את הערך של העוגיה בכלי המפתחים וזהו. גם את זה ראיתי.
וכמובן שאני אציין שוב שה-Privilege Escalation הזה נקרא אנכי, או Vertical Privilege Escalation. כי אנחנו מתקדמים במעלה התפקידים.
Privilege Escalation אופקי
יש כמובן גם Horizontal Privilege Escalation או אופקי. שבו אני נשאר באותו תפקיד, אבל מקבל גישה למשאבים שאני לא צריך לראות – כמו למשל גישה לפרטים של משתמשים אחרים. נדגים עם הדוגמה הקודמת:
app.get('/user/:id', (req, res) => {
const userId = req.params.id;
if (req.user.id === userId) {
res.send('User Profile');
} else {
res.status(403).send('Forbidden');
}
});
במקרה הזה, כשמשתמש מנסה להכנס ל user/123456 – נעשית בדיקה עם ה-req.user.id שלו שווה ל 123456. אבל אנחנו זוכרים, מהדוגמה הקודמת ש-req.user.id הוא פרמטר שתלוי במימוש שלו במערכת. ואם למשל ה-id הזה לא מגיע הישר ממסד הנתונים אלא מקלט של המשתמש – אז גם פה ניתן לזייף.
כמובן שבישראל כמו בישראל – לא מעט פעמים אין בכלל access control ולא נעשית בדיקה אם אני יכול להכנס למשאב ואפילו אפשר להכנס כמשתמש אנונימי. זה נקרא Broken Access Control אבל על זה אנחנו לא מדברים פה. אנחנו מדברים על משתמש רשום שיכול לגשת למידע באותה שכבה שלו.
מניעה
במקרה הזה אין פתרון אחד כללי בדמות כלי או טכניקה. בדרך כלל הפרצות האלו הן פרצות שנוצרו בגלל רשלנות בתכנות או בתכנון המערכת. מערכת הרשאותוניהול היא דבר שצריכים לחשוב עליו מבחינה הוליסטית ולתכנן אותו. בתהליך התכנון צריך להתחשב בטכניקה שנקראת RBAC (אני קורא לזה רבאק, אבל זה רק אני והמוח המוזר שלי). בגדול RBAC, או בעברית בקרת גישה מבוססת תפקידים, היא שיטה לניהול והרשאות גישה למערכות – גם ווב וגם אחרות. בשיטה זו, ההרשאות למשתמשים ניתנות על פי התפקידים שהם צריכים לקבל וכל תפקיד מקבל סט מסוים של הרשאות המאפשרות ביצוע פעולות מסוימות. לא isAdmin ומשחקים אחרים אלא מקום אחד מרכזי שבו מקבלים את התפקיד. כאשר לכל תפקיד אנו נותנים הרשאה מינימלית. מה זה? עקרון ההרשאה המינימלית הוא עקרון אבטחה שמטרתו לנהל את התפקידים כך שהסיכון יהיה יותר קטן. העיקרון קובע שתפקידים צריכים לקבל רק את ההרשאות הדרושות לביצוע המשימות שהוקצו להם, ולא יותר מכך. זה נשמע קצת מוזר – אבל בגדול הרבה פעמים אנו נותנים הרשאות מרחיקות לכת יותר וכל מי שנתן למשחק כלשהו הרשאת admin יודע על מה אני מדבר.
פריצות שהיו
היו רבות אבל הדוגמה הטובה ביותר היא הפריצה של Okta שבה, על פי הדיווחים, התוקפים ישבו במערכת בסבלנות עד שהצליחו להשיג הרשאות יותר גבוהות.
גם פרצה באלמנטור שתוקנה (אך לא נוצלה על ידי תוקפים) נגרמה על ידי יכולת של משתמש אנונימי לקבל הרשאות של משתמשים אחרים. יש הסבר מאד מאד נאה ומעניין פה. מבהיר שאני משתמש מרוצה של אלמנטור ודברים כאלו יכולים להתרחש בכל חברה.
מקורות לקריאה נוספת בעברית
3 תגובות
פוסט נהדר ומרתק!
מעשיר את הידע.
אחלה הסבר!
אשמח להתפלפל איתך, רן, בנוגע להגדרה של ״הסלמת הרשאות״ כ-״מתקפה״.
עד עתה חשבתי על ״הסלמת הרשאות״ יותר כ-״חולשה״ וכשלב אחד בתוך מתקפה כוללת יותר. שהרי הסלמת ההרשאות עצמה אינה פוגענית אלא מה שעושים לאחר קבלת ההרשאות הנרחבות יותר.
דעתך?
אצלנו עובדים עם Okta, ועל כל בקשת api יש middleware שבודק Auth על-ידי וולידציה של cookieSession שנשתלת בשלב הלוג-אין. ה session עצמו הוא טוקן שאוקטה מג'נרט ועושה וולידציה כל פעם.