הרשאות API: RBAC, ABAC ו-ReBAC והמלכודת של Broken Object Level Authorization

מאת צוות מדיה דיל · 06.08.2026 · API Engineering · 8 דק׳

ידיעת מי הצרכן היא רק חצי הבעיה. מדריך עומק להרשאה נכונה ב-API — מ-RBAC פשוט ועד BOLA, הפרצה הנפוצה ביותר ב-API-ים אמיתיים.

ידיעת מי הצרכן היא רק חצי הבעיה. השאלה השנייה, ולא פחות קריטית, היא מה מותר לו לעשות. הרשאה (authorization) היא השכבה שמחליטה אם משתמש מזוהה יכול לגשת למשאב ספציפי, לבצע פעולה מסוימת, או לראות שדה מסוים בתשובה. הבלבול בין authentication ל-authorization הוא אחד המקורות הנפוצים ביותר לפרצות אבטחה ב-API-ים — endpoint שבודק רק שהטוקן חוקי, בלי לוודא שהמשתמש בכלל מורשה לגשת לרשומה הספציפית שהוא מבקש, הוא הדוגמה הקלאסית ביותר.

OWASP, הארגון המוביל בתחום אבטחת אפליקציות web, מציב את Broken Object Level Authorization (BOLA) בראש רשימת פרצות האבטחה הנפוצות ביותר ב-API-ים — endpoint כמו GET /orders/{id} שבודק רק שהמשתמש מחובר, אבל לא שהוא בעל ה-order הספציפי, מאפשר לכל משתמש מחובר לצפות בהזמנות של כל משתמש אחר פשוט על ידי שינוי מספר ב-URL. זו לא פרצה תיאורטית — היא אחת הבעיות הנפוצות ביותר שנמצאות בבדיקות אבטחה של API-ים אמיתיים בפרודקשן, ולעיתים קרובות נשארת בלתי מזוהה שנים לפני שמישהו מנצל אותה.

RBAC: המודל הבסיסי והנפוץ ביותר

Role-Based Access Control הוא המודל הפשוט והנפוץ ביותר: כל משתמש מקבל תפקיד אחד או יותר (admin, editor, viewer), וכל תפקיד מוגדר עם רשימת הרשאות קבועה מראש. היתרון המרכזי הוא פשטות — קל להבין, קל לתחזק, וקל לבדוק "האם למשתמש הזה יש את התפקיד X". המגבלה היא שהמודל גס יחסית: קשה לבטא הרשאות ברמת רשומה בודדת ("רק בעל ההזמנה יכול לראות אותה") רק דרך תפקידים, כי תפקיד מגדיר יכולת כללית ולא הקשר ספציפי.

{
  "user_id": "u_42",
  "roles": ["editor", "billing_viewer"]
}

בפועל, רוב המערכות משתמשות ב-RBAC כשכבה ראשונה וגסה (coarse-grained) — למשל "רק admin יכול לגשת ל-/admin/*" — ומוסיפות עליה שכבה עדינה יותר (fine-grained) לבדיקות ברמת רשומה בודדת, שמפורטת בהמשך.

ABAC: כשתפקיד קבוע לא מספיק

Attribute-Based Access Control מרחיב את המודל: במקום תפקיד קבוע, ההחלטה מתקבלת בזמן ריצה על בסיס תכונות (attributes) של המשתמש, המשאב, והפעולה. למשל: "עורך יכול לערוך מסמך רק אם הוא בבעלות הצוות שלו, ורק בשעות העבודה, ורק אם המסמך לא ננעל לעריכה על ידי מישהו אחר". המודל הזה גמיש משמעותית יותר, אבל גם מורכב יותר לתחזוקה ולבדיקה — קשה יותר לענות בוודאות על השאלה "מי בדיוק יכול לגשת למה" כי התשובה תלויה בהקשר דינמי ולא ברשימה סטטית.

ABAC מתאים במיוחד לארגונים עם דרישות הרשאה מורכבות שלא ניתן לבטא ב-RBAC פשוט — למשל מערכות רב-דיירים (multi-tenant) עם היררכיית ארגונים, שבהן ההרשאה תלויה גם בתפקיד וגם בשיוך הארגוני וגם בהיררכיית הדיווח בין משתמשים. המחיר הוא שצריך מנוע כללים (policy engine) ייעודי כדי לנהל את המורכבות הזו, ולא מספיק בדיקת if-else פשוטה מפוזרת בקוד.

ReBAC: הרשאה מבוססת יחסים

Relationship-Based Access Control, שהתפרסם בעיקר דרך מערכת Zanzibar של גוגל (שעליה מבוססים Google Docs ו-YouTube), מגדיר הרשאה דרך גרף יחסים בין ישויות — "משתמש X הוא owner של מסמך Y", "משתמש Z הוא member של תיקיה שמכילה את מסמך Y ולכן viewer שלו בירושה". המודל הזה מתאים במיוחד למערכות שיתוף ותוכן היררכי, שבהן הרשאות עוברות בירושה דרך מבנה עץ או גרף — בדיוק כמו הרשאות תיקיות וקבצים ב-Google Drive, שבהן הרשאה על תיקייה מתפשטת אוטומטית לכל הקבצים בתוכה.

מימוש ReBAC מלא דורש תשתית ייעודית (כמו OpenFGA, קוד פתוח בהשראת Zanzibar) שיודעת לענות במהירות על שאילתות כמו "האם למשתמש X יש הרשאת read על משאב Y" גם כשהתשובה תלויה בשרשרת ירושה ארוכה. לפרויקטים קטנים בלי צורך אמיתי בשיתוף מורכב, זו לרוב תוספת מורכבות שלא מצדיקה את עצמה, ועדיף RBAC פשוט עם בדיקות בעלות ישירות.

אכיפה ברמת Object: המקום שהכי הרבה פרצות קורות

גם עם מודל הרשאה מתוחכם ברמה גלובלית, הנקודה הקריטית ביותר בפועל היא אכיפה ברמת רשומה בודדת (object-level) בכל endpoint שמקבל מזהה. הכלל הפשוט אך הקריטי: כל query שמביא רשומה לפי id חייב לכלול גם תנאי בעלות או הרשאה, לא רק את ה-id עצמו.

-- לא בטוח:
SELECT * FROM orders WHERE id = ?

-- בטוח:
SELECT * FROM orders WHERE id = ? AND user_id = ?

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

הרשאה ברמת שדה: מעבר לרשומה השלמה

לעיתים ההרשאה לא בינארית ברמת רשומה שלמה, אלא ברמת שדה בודד — למשל שני משתמשים יכולים לראות את אותה הזמנה, אבל רק אחד מהם (הבעלים) רואה את פרטי כרטיס האשראי המלאים, בעוד השני רואה גרסה מוסתרת חלקית. זו הרשאה עדינה יותר שקשה לבטא במודל RBAC/ABAC פשוט, ולרוב דורשת לוגיקת serialization ייעודית ברמת ה-DTO שמחליטה אילו שדות לכלול בהתאם להקשר המבקש. חשוב לתכנן את זה בשכבת ה-representation, לא לסמוך על ה-client שיחליט מה להציג ומה להסתיר — לוגיקה שרצה רק בצד client לא מגנה על כלום, כי כל אחד יכול לפנות ל-API ישירות ולעקוף את ה-UI.

Policy Engines: כשהלוגיקה גדולה מדי לקוד מפוזר

כשהרשאה מורכבת מספיק — כללי ABAC רבים, תלות בהקשר ארגוני, ותנאים משתנים — פיזור הלוגיקה כ-if-else בכל endpoint הופך בלתי ניתן לתחזוקה, וגרוע מכך, קשה לבדוק ולוודא נכונות שלו. פתרון נפוץ הוא policy engine נפרד — כלים כמו Open Policy Agent (OPA) מאפשרים להגדיר כללי הרשאה בשפת policy ייעודית (Rego), נפרדת מקוד היישום, ולהריץ אותם כשירות עצמאי או כספרייה מוטמעת. היתרון המרכזי הוא ריכוז: כל כללי ההרשאה נמצאים במקום אחד, ניתנים לבדיקה עצמאית, ואפשר לשנות אותם בלי לגעת בקוד היישום עצמו ולפרוס אותו מחדש.

המחיר הוא שכבת תשתית נוספת ועקומת למידה לשפת policy חדשה, ולכן policy engine נפרד משתלם בעיקר בארגונים עם כללי הרשאה מורכבים באמת ותלות רבת-שירותים בהם — לא לפרויקט קטן עם RBAC פשוט, ששם קוד ישיר בתוך ה-middleware עדיין הפתרון הפשוט והברור ביותר.

GraphQL ו-gRPC: הרשאה בעולם שאינו REST

ב-GraphQL, בדיקת הרשאה מורכבת יותר כי query בודד יכול לגעת בהרבה ישויות שונות בו-זמנית — צריך לבדוק הרשאה בכל resolver בנפרד, לא רק ב-entry point של ה-query, אחרת client יכול לעקוף בדיקה ברמת שדה עמוק דרך nested query שלא עבר דרך הביקורת המקורית. ב-gRPC, ההרשאה בדרך כלל נאכפת ב-interceptor שרץ לפני כל method call, בדומה ל-middleware ב-REST, אבל צריך לזכור שגם streaming calls (server streaming, bidirectional) דורשים בדיקת הרשאה מתמשכת אם ההרשאה עשויה להשתנות תוך כדי stream ארוך-טווח, ולא רק בדיקה חד-פעמית בתחילת החיבור.

טעויות נפוצות בפרודקשן

הטעות הראשונה, והחמורה ביותר, היא BOLA — כפי שהוזכר, endpoint שבודק אימות אבל לא בעלות. הפתרון הוא בדיקת בעלות אוטומטית ועקבית, לא ידנית לכל endpoint. טעות שנייה היא הסתמכות על "security through obscurity" — מזהי רשומות רציפים וניחושים קלים (id=1001, id=1002) שהופכים סריקה שיטתית לקלה במיוחד; שימוש ב-UUID אקראיים כמזהים ציבוריים, יחד עם בדיקת הרשאה אמיתית, מפחית את משטח ההתקפה גם אם בדיקת ההרשאה נכשלת מסיבה כלשהי.

טעות שלישית היא הרשאה שנבדקת רק ב-frontend ולא ב-API עצמו — קוד JavaScript שמסתיר כפתור "מחק" ממשתמש רגיל לא מונע ממנו לשלוח בקשת DELETE ישירות ל-API באמצעות curl. כל בדיקת הרשאה חייבת להתקיים בצד השרת, ללא יוצא מן הכלל, גם אם יש גם בדיקה כפולה ב-frontend לחוויית משתמש טובה יותר. טעות רביעית היא הרשאות שלא מתעדכנות מיד כשמשתמש מוסר מתפקיד — אם המידע נשמר ב-JWT עם תוקף ארוך, הוא ממשיך לפעול לפי ההרשאות הישנות עד שהטוקן פג תוקף, מה שדורש תכנון מפורש של תוקף קצר או מנגנון ביטול, כפי שהרחבנו במדריך אימות API. טעות חמישית, נפוצה בעיקר בממשקי ניהול (admin panels), היא היעדר עקרון ה-least privilege — משתמשי admin מקבלים גישה גורפת לכל הפעולות במקום הרשאות ממוקדות לפי הצורך בפועל, מה שהופך כל חשבון admin שנפרץ לאסון מלא במקום לנזק מוגבל. עקרון ה-least privilege אומר שכל תפקיד מקבל את מינימום ההרשאות הדרוש לו לתפקד, ולא יותר "ליתר ביטחון" או נוחות.

מתי כל מודל מתאים

RBAC מתאים לרוב המערכות עם היררכיית תפקידים פשוטה יחסית. ABAC מתאים למערכות עם כללי הרשאה מורכבים ותלויי-הקשר, במיוחד ב-multi-tenant. ReBAC מתאים למערכות שיתוף ותוכן היררכי עם ירושת הרשאות. כמעט תמיד שווה לשלב RBAC גס ברמת endpoint עם בדיקת בעלות עדינה ברמת רשומה — זה נותן כיסוי טוב לרוב המקרים בלי המורכבות של מנוע כללים מלא. הרחבנו על השילוב עם אימות ועם OpenID Connect במדריך OpenID Connect.

בדיקות אוטומטיות: איך מוודאים שהרשאה לא נשברת בשקט

הרשאה היא מהתחומים שהכי קל לשבור בטעות תוך כדי refactor רגיל — מפתח שמשנה query כדי לשפר ביצועים ובטעות מוריד את תנאי ה-user_id, או צוות שמוסיף endpoint חדש ושוכח להוסיף את בדיקת ההרשאה שקיימת בכל שאר ה-endpoints הדומים. בלי בדיקות אוטומטיות ייעודיות, השבירה הזו לא מתגלה עד שמישהו מנצל אותה בפועל, ולעיתים לא מתגלה בכלל.

הפתרון המומלץ הוא suite של בדיקות authorization ייעודיות, נפרד מבדיקות הפונקציונליות הרגילות — לכל endpoint, בדיקה מפורשת שמוודאת שמשתמש A לא יכול לגשת למשאב של משתמש B, ושמשתמש עם תפקיד נמוך לא יכול לבצע פעולה שדורשת תפקיד גבוה. בדיקות כאלה צריכות לרוץ כחלק מכל pipeline של CI, לא כתהליך ידני שנעשה רק לפני שחרור גדול, כי בדיוק בשינויים "קטנים" ושגרתיים קורית רוב השבירה בפועל.

סיכום

הרשאה היא השכבה שמתרגמת "מי אתה" ל"מה מותר לך" — והיא לרוב המקום שבו נופלות רוב פרצות האבטחה ב-API-ים אמיתיים, כי היא דורשת בדיקה עקבית בכל endpoint, לא רק פעם אחת בכניסה למערכת. הבחירה במודל (RBAC, ABAC, ReBAC) פחות קריטית מהמשמעת של אכיפה עקבית ברמת רשומה בודדת בכל מקום שבו יש מזהה שמגיע מה-client.

תגיות: API authorization · RBAC · ABAC · BOLA · OWASP API Security · least privilege · policy engine

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