ABAC ב-SaaS: הרשאות מבוססות תכונות כשתפקידים כבר לא מספיקים

מאת צוות מדיה דיל · 02.08.2026 · SaaS Architecture · 9 דק׳

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

הרגע שבו RBAC נשבר

יש נקודה מוכרת בחיים של כל SaaS גדל: מישהו מבקש הרשאה שהיא לא מי אתה אלא מה ההקשר. עובד שיכול לערוך רק מסמכים שהוא יצר. מנהל אזורי שרואה רק לקוחות באזור שלו. חוזה שנגיש רק בשעות העבודה של המדינה הרלוונטית. ברגע שמנסים לפתור את זה עם RBAC, מקבלים תפקיד לכל שילוב אפשרי - Editor-Own-Docs, Regional-Manager-North, Regional-Manager-South - וזה מתפוצץ לאקספוננציה של תפקידים שאי אפשר לתחזק. Attribute-Based Access Control (ABAC) בנוי בדיוק בשביל המקרה הזה: במקום לשאול איזה תפקיד יש למשתמש, השאלה היא האם השילוב של תכונות המשתמש, המשאב, הפעולה וההקשר מקיים כלל מסוים.

ארבעת המרכיבים של כל החלטת ABAC

כל מנוע ABAC מבוסס על ארבע קטגוריות תכונות. Subject attributes - מי המשתמש: תפקיד, מחלקה, רמת clearance, tenant. Resource attributes - מה המשאב: הבעלים שלו, התיוג שלו, הרגישות שלו, ה-tenant שהוא שייך אליו. Action - מה מנסים לעשות: read, write, delete, export. ו-Environment attributes - ההקשר: שעה, מיקום גיאוגרפי, סוג המכשיר, רמת האבטחה של החיבור. כלל ABAC טיפוסי נראה כך: אפשר גישת read למשאב מסוג invoice אם ה-tenant_id של המשתמש שווה ל-tenant_id של המשאב, וגם (התפקיד הוא finance או המשתמש הוא הבעלים של המשאב), וגם השעה היא בין 06:00 ל-22:00 בזמן מקומי.

Policy Language: איך כותבים כללים שאפשר לתחזק

הכתיבה הישירה של תנאי ABAC כ-if statements בקוד היא מלכודת - היא בלתי אפשרית לביקורת (audit) ובלתי אפשרית לשינוי בלי דיפלוי. הפתרון המקובל בתעשייה הוא שפת policy ייעודית, כאשר הבולטת ביותר היא Rego של Open Policy Agent, שמאפשרת להגדיר כללים כנתונים מוצהרים ולא כקוד אימפרטיבי. חלופה קלה יותר היא JSON-based policy rules פנימיים, עם evaluator ייעודי שממפה תנאים לפונקציות בדיקה. הערך המרכזי הוא הפרדה בין הכללים לקוד האפליקציה - כך אפשר לשנות מדיניות הרשאות בלי דיפלוי, ואף לתת ללקוחות Enterprise לנהל את הכללים שלהם דרך UI ייעודי.

allow {
  input.action == 'read'
  input.resource.type == 'invoice'
  input.resource.tenant_id == input.subject.tenant_id
  input.subject.role == 'finance'
}

Policy Decision Point מול Policy Enforcement Point

ארכיטקטורה נכונה מפרידה בין שתי נקודות: ה-PEP (Enforcement Point) הוא הקוד שבודק בכל endpoint האם לאפשר את הפעולה, וה-PDP (Decision Point) הוא השירות שמקבל את ההחלטה בפועל בהתבסס על התכונות והכללים. ההפרדה הזו מאפשרת להריץ את ה-PDP כשירות עצמאי, אולי אפילו כ-sidecar לצד כל שירות, כך שהוא ניתן לעדכון, בדיקה, ובקרה בנפרד מהקוד העסקי. חסרון של הפרדה מלאה הוא latency נוסף על כל בקשה, ולכן ברוב המערכות הפרודקשן ה-PDP רץ in-process או כ-library מוטבעת, עם sync תקופתי של כללי המדיניות מהשרת המרכזי.

ביצועים: הבעיה האמיתית של ABAC

ה-flexibility של ABAC באה במחיר. RBAC אפשר לחשב cache פשוט של role permissions, אבל ב-ABAC ההחלטה תלויה בתכונות המשאב הספציפי, ולכן אי אפשר לשמור החלטה גורפת ל-cache. הפתרון בפרודקשן הוא לרוב שכבתי: קודם בודקים סינון גס ברמת RBAC (למשל, יש למשתמש בכלל הרשאת read על invoices), ורק אז מריצים כללי ABAC עדינים על תת-הקבוצה שעברה את הסינון הראשוני. גישה נוספת היא לדחוף חלק מהתנאים ישירות לתוך שאילתת ה-DB עצמה כ-WHERE clause, כך שהמסד נתונים מבצע את הסינון במקום לטעון את כל הרשומות ולסנן אותן באפליקציה.

ABAC ב-Row-Level Security

מסדי נתונים כמו PostgreSQL תומכים ב-Row-Level Security (RLS) שמאפשר להטמיע חלק מלוגיקת ABAC ישירות ברמת ה-DB. זה יתרון עצום מבחינת ביטחון - גם אם מפתח שוכח לבדוק הרשאה בקוד האפליקציה, ה-DB עצמו חוסם גישה לא מורשית. החיסרון הוא שקשה יותר לבדוק ולתעד policy שמפוזרת בין הקוד ל-DB, ולכן ארגונים בשלים נוטים להגדיר RLS כשכבת הגנה אחרונה (defense in depth) ולא כמנגנון היחיד לאכיפת הרשאות.

טעויות נפוצות

הטעות הראשונה היא לבנות ABAC גנרי מדי מההתחלה - מנוע כללים גמיש שאף אחד לא מבין ואף אחד לא סומך עליו. עדיף להתחיל עם קבוצה קטנה של תכונות קריטיות ולהרחיב בהדרגה. הטעות השנייה היא שכפול לוגיקת ABAC בין Frontend ל-Backend בלי single source of truth - זה מוביל לחוסר עקביות שבה ה-UI מציג אפשרות שה-API חוסם, או גרוע מכך, ההפך. הטעות השלישית היא הזנחת ה-audit trail: מכיוון שכללי ABAC מורכבים, קריטי לתעד לא רק מה קרה אלא גם למה - איזה כלל ספציפי אפשר או חסם כל פעולה.

RBAC ו-ABAC יחד, לא במקום זה

המודל הנפוץ ביותר בפרודקשן הוא היברידי: RBAC כשכבה ראשונה שמגדירה יכולות רחבות (מה בעל תפקיד finance יכול לעשות בעיקרון), ו-ABAC כשכבה שנייה שמצמצמת את זה להקשר הספציפי (רק על invoices של ה-tenant שלו, ורק בשעות העבודה). זו הגישה שאנחנו במדיה דיל ממליצים עליה כברירת מחדל ללקוחות שמגיעים עם דרישות הרשאה מורכבות - לא לזרוק את RBAC הקיים אלא להוסיף עליו שכבת ABAC ממוקדת רק היכן שבאמת נדרשת גמישות הקשרית.

Debugging: כשההרשאה נדחית ולא ברור למה

אחד הכאבים הגדולים ביותר במעבר ל-ABAC הוא חוסר שקיפות בהחלטת דחייה - משתמש מקבל 403 Forbidden בלי שום הסבר למה, ולעיתים אפילו הצוות התומך מתקשה להבין איזה כלל בדיוק חסם את הגישה מתוך עשרות כללים פעילים. הפתרון הוא Decision Explanation - כל תשובה שלילית של ה-PDP חייבת להחזיר, לפחות בלוג הפנימי, את הכלל הספציפי שגרם לדחייה ואת התכונות שהובילו להחלטה. מנועי Policy כמו OPA תומכים בזה מובנה דרך trace mode, שמראה את כל שלבי ההערכה. בלי היכולת הזו, כל תלונת לקוח על ״אני לא רואה את המסמך שאני אמור לראות״ הופכת לחקירה ארוכה בקוד במקום בדיקה של כמה שניות בלוג ההחלטות.

ABAC ו-Consent-Based Access: כשההרשאה תלויה בהסכמת המשתמש

תחת רגולציות כמו GDPR, יש מקרים שבהם גישה למידע מסוים תלויה לא רק בתפקיד הארגוני אלא בהסכמה מפורשת שנתן בעל הנתונים (Data Subject Consent) - למשל, גישה לנתוני בריאות של עובד רק אם הוא אישר שיתוף אותם עם HR. זהו מקרה קלאסי שבו attribute דינמי (consent_status, שיכול להשתנות בכל רגע כשהמשתמש מבטל הסכמה) חייב להיכנס לשיקול ההרשאה בזמן אמת, לא רק בזמן ה-login. זה מחזק שוב את הצורך בכך שה-PDP יבדוק תכונות עדכניות מהמקור בזמן ההחלטה, ולא יסתמך על cache ישן שעלול להחזיק סטטוס הסכמה שכבר בוטל.

ניהול תכונות (Attribute Sources) ואמינותן

איכות החלטת ABAC תלויה לגמרי באיכות התכונות שמזינות אותה. תכונה שמקורה בטבלה פנימית מעודכנת בזמן אמת (כמו tenant_id) אמינה מאוד, אבל תכונה שמגיעה ממקור חיצוני (כמו סטטוס אבטחת מכשיר מ-MDM חיצוני, או מיקום גיאוגרפי מ-IP lookup) עשויה להיות מיושנת, לא מדויקת, או זמנית לא זמינה. מערכת ABAC בשלה מגדירה במפורש לכל תכונה את מקור האמת שלה, את תדירות הרענון הנדרשת, ואת ההתנהגות הרצויה כשמקור התכונה לא זמין - Fail Open (אפשר גישה בברירת מחדל, מסוכן) או Fail Closed (חסום גישה בברירת מחדל, בטוח יותר אך פוגע בזמינות). ברוב מקרי השימוש הרגישים - פיננסים, בריאות, נתונים אישיים - הכלל הנכון הוא Fail Closed: אם אי אפשר לוודא תכונה קריטית, עדיף לחסום גישה זמנית מאשר לקחת סיכון.

ABAC ב-UI: הצגת סיבת הדחייה למשתמש הקצה

מעבר לחשיפת סיבת הדחייה לצוות הפיתוח (Debugging שתואר קודם), יש גם ערך משמעותי בהצגת סיבה ידידותית למשתמש הקצה עצמו - לא ״403 Forbidden״ גנרי, אלא הודעה שמסבירה בבירור מדוע הגישה נדחתה ומה אפשר לעשות (למשל, ״המסמך הזה נגיש רק בשעות העבודה של המשרד שלך״ או ״אתה יכול לגשת רק למסמכים שאתה הבעלים שלהם״). זה דורש שהמנוע יחזיר לא רק allow/deny בוליאני אלא קוד סיבה מובנה שה-Frontend יכול לתרגם להודעה אנושית. השקעה קטנה יחסית בהצגת הודעות ברורות חוסכת המון פניות תמיכה, כי משתמשים שמבינים למה נדחו הרבה פחות סביר שיפתחו כרטיס תמיכה מיותר.

סיכום

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

תגיות: ABAC · Attribute-Based Access Control · SaaS Architecture · Authorization · Policy Engine · Row-Level Security · OPA

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