RAG Access Control: איך מונעים מבוט AI לחשוף מידע שהמשתמש לא אמור לראות

מאת צוות מדיה דיל · 05.08.2026 · Data Engineering · 10 דק׳

וקטור לא יודע מי שואל אותו. מדריך מעמיק לאכיפת הרשאות ב-RAG: Document-Level Security, Filtered Retrieval וטעויות נפוצות שחושפות מידע רגיש.

תרחיש שקורה יותר ממה שרוצים להודות בו: ארגון בונה עוזר AI פנימי מעל Confluence ו-Google Drive, כולל מסמכי HR עם נתוני שכר, מסמכי משפטי עם חוזים, ותיעוד טכני. חודשיים אחרי ההשקה מתגלה שעובד זוטר שאל את הבוט "מה השכר של מנהל הצוות שלי" וקיבל תשובה — כי מסמך השכר היה חלק מהאינדקס הוקטורי, ואף אחד לא בדק שההרשאות שהיו קיימות במקור (Confluence Permissions) נשמרו גם באינדקס. זו לא תקלה נדירה — זו התוצאה הצפויה כשבונים RAG בלי Access Control מובנה מהיסוד. וקטור, בניגוד למסמך במערכת ניהול תוכן, לא "יודע" מי מורשה לראות אותו — אלא אם בונים את זה במפורש.

למה הרשאות RAG הן בעיה שונה מהרשאות אפליקטיביות רגילות

במערכות מסורתיות, בקרת גישה נאכפת ברמת ה-Query: משתמש מבקש רשומה, המערכת בודקת הרשאה, ומחזירה או חוסמת. ב-RAG, השכבה הנוספת של Retrieval מבוסס Similarity Search לא "יודעת" באופן טבעי להתחשב בהרשאות — היא פשוט מחזירה את ה-chunks הכי דומים סמנטית לשאילתה, ללא קשר למי שואל. אם לא בונים סינון הרשאות כחלק אינטגרלי מתהליך ה-Retrieval, ה-LLM מקבל context שכולל מידע שהמשתמש לא אמור לראות, ואז — גם אם ננסה להנחות אותו בפרומפט "אל תחשוף מידע רגיש" — קיים סיכון ממשי שהוא יעשה זאת בכל זאת, כי המידע כבר נמצא בהקשר שהוא רואה.

הקשר רגולטורי: למה זה לא רק שאלה טכנית

בתעשיות מוסדרות — בנקאות, ביטוח, בריאות — חשיפת מידע לא מורשית דרך מערכת AI היא לא רק תקלת מוצר אלא עלולה להיות הפרת רגולציה עם השלכות משפטיות ממשיות. רגולטורים בישראל ובעולם מתחילים להתייחס למערכות AI כאל מערכות מידע רגילות מבחינת חובות אבטחה — מה שאומר שאותם עקרונות שחלים על בסיסי נתונים (least privilege, הפרדת תפקידים, audit trail) חלים באותה מידה על מערכות RAG. ההבדל הוא שברוב הארגונים עדיין אין תקנים ברורים ומוכרים ל"איך עושים את זה נכון ב-RAG", מה שהופך את ההחלטות הארכיטקטוניות שתוארו במאמר הזה לא רק לשיקול הנדסי אלא לשיקול תאימות שצריך לתעד ולהיות מסוגלים להסביר בביקורת.

שני מודלים לאכיפת הרשאות: Pre-Filtering מול Post-Filtering

יש שתי גישות עקרוניות. Post-Filtering: מבצעים Similarity Search רגיל ומקבלים את ה-top-K chunks, ורק אחר כך מסננים לפי הרשאות המשתמש. הגישה הזו פשוטה להטמעה אך פגומה בבסיסה: אם רוב התוצאות הכי רלוונטיות נחסמות בגלל הרשאות, נשארים עם פחות מ-K תוצאות (או אפס), ואיכות ה-Retrieval נפגעת קשות. Pre-Filtering: משלבים את תנאי ההרשאה כחלק מהשאילתה עצמה לווקטור DB — כלומר, ה-Similarity Search מתבצע רק בתת-הקבוצה של הווקטורים שהמשתמש מורשה לראות מלכתחילה. רוב מסדי הנתונים הוקטוריים המודרניים (Pinecone, Weaviate, Qdrant) תומכים ב-Metadata Filtering שמאפשר בדיוק את זה: לצרף ל-query תנאי כמו allowed_groups CONTAINS user.group, ולקבל top-K אמיתי מתוך הסט המורשה בלבד.

מודל ה-ACL: מה שומרים על כל Chunk

כדי ש-Pre-Filtering יעבוד, כל chunk באינדקס חייב לשאת metadata של הרשאות שמשקף את המקור המקורי במדויק. המודל הנפוץ ביותר הוא ACL מבוסס קבוצות: לכל chunk רשימת group_ids שמורשים לגשת אליו, שמסונכרנת עם מערכת ההרשאות המקורית (Google Groups, Active Directory, הרשאות Confluence Space). זה דורש שהפייפליין ingestion (ראו Knowledge Ingestion Pipelines) ימשוך לא רק את תוכן המסמך אלא גם את מטא-דאטה ההרשאות שלו, וישמור אותו מסונכרן — כולל טיפול בשינויי הרשאה שקורים גם בלי שהתוכן עצמו השתנה, למשל כשמישהו מוסר מקבוצת גישה.

results = vector_db.query(
    vector=query_embedding,
    top_k=8,
    filter={"allowed_groups": {"$in": user.group_ids}}
)

הרשאות שליליות (Deny Rules) לצד הרשאות חיוביות

רוב המודלים שתוארו למעלה מניחים מודל "אפשר" (allow-list) — chunk נגיש רק אם קבוצת המשתמש מופיעה ברשימת ה-allowed_groups שלו. ברוב המקרים זה נכון ומספיק. אבל יש מצבים שבהם צריך גם חוקי "אסור" מפורשים (deny rules) שגוברים על allow: למשל עובד שנמצא תחת חקירה פנימית ואמור להיחסם ממידע מסוים באופן זמני, גם אם הוא חבר בקבוצה שבדרך כלל מורשית. עיצוב שתומך רק ב-allow-list לא יכול לבטא מצב כזה בלי לשנות את שיוך הקבוצות עצמו, מה שמסורבל ומועד לטעויות. עיצוב מתקדם יותר בודק קודם deny rules (אם קיים deny מפורש — חוסמים, גם אם יש allow), ורק אחר כך allow rules. זו תוספת מורכבות שלא כל מערכת צריכה, אבל ארגונים עם דרישות אבטחה גבוהות במיוחד — סקטור ביטחוני, פיננסי — כמעט תמיד יזדקקו לה במוקדם או במאוחר.

סנכרון הרשאות: הבעיה שקשה ביותר בפועל

האתגר האמיתי הוא לא הפילטור עצמו אלא לשמור על הרשאות מעודכנות. הרשאות משתנות בתדירות גבוהה יותר מתוכן — עובד עוזב צוות, מסמך משתף חדש, קבוצת גישה מתעדכנת. אם סנכרון ההרשאות מתבצע רק כחלק מריצת ה-ingestion הרגילה (למשל פעם ביום), נוצר חלון זמן שבו משתמש שכבר הוסר מקבוצה עדיין רואה תוכן שהוא לא אמור לגשת אליו דרך הבוט, גם אם הוא כבר לא רואה אותו במקור המקורי. הפתרון הנכון הוא להאזין ל-Webhooks של שינויי הרשאה בנפרד מסנכרון תוכן, ולעדכן metadata של הרשאות במהירות גבוהה יותר משאר ה-pipeline — שינוי הרשאה הוא אירוע קריטי אבטחתית שדורש עדיפות עיבוד גבוהה יותר מעדכון תוכן רגיל.

הגנת עומק: מה קורה כשה-Pre-Filtering נכשל

גם עם Pre-Filtering תקין, ראוי להוסיף שכבת בקרה נוספת — Defense in Depth. שכבה זו כוללת Post-Generation Check: לפני שהתשובה חוזרת למשתמש, בדיקה אוטומטית (יכולה להיות מודל קטן וזול) שסורקת אם התשובה מכילה דפוסים של מידע רגיש (מספרי שכר, מספרי ת.ז., מונחים משפטיים מסווגים) ומשווה מול פרופיל ההרשאה של המשתמש. זו לא תחליף לפילטור נכון ב-Retrieval, אלא רשת ביטחון למקרה של תקלת סנכרון או באג. בנוסף, לוג מלא של כל שאילתה עם ה-chunks שהוחזרו (ראו לינאז' במאמר על Data Governance) מאפשר לאתר ולתקן מקרי חשיפה בדיעבד, גם אם המניעה בזמן אמת לא הייתה מושלמת.

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

הטעות המרכזית: להסתמך על "prompt engineering" כדי למנוע חשיפת מידע רגיש — לבקש מהמודל "אל תגלה מידע על שכר" בלי לחסום את המידע מלהגיע ל-context מלכתחילה. זו לא בקרת אבטחה אמיתית, אלא הצעה שהמודל עלול להתעלם ממנה תחת ניסוח שאלה יצירתי — למשל שאלה שמנוסחת בעקיפין, בשפה זרה, או כחלק מתרחיש היפותטי שמטרתו לעקוף את ההנחיה. הטעות השנייה: לבצע Post-Filtering במקום Pre-Filtering, מה שפוגע גם באבטחה וגם באיכות (top-K חסר). השלישית: לשכוח לטפל בהרשאות ברמת namespace שלם ולא רק ברמת chunk בודד — למשל מקור שלם (כל Google Drive של מחלקת HR) שאמור להיות מוסתר לגמרי מקבוצות מסוימות. הרביעית: אי-בדיקה תקופתית (audit) שההרשאות באינדקס אכן תואמות למקור — פערים מצטברים עם הזמן אם אין תהליך ולידציה שוטף. טעות חמישית, שקל לפספס: לשכוח שגם דפוס השאילתות עצמו יכול לחשוף מידע במקרים קיצוניים — אם תוקף פוטנציאלי שולח שאילתות רבות ובוחן אילו מהן מחזירות תוצאות "קרובות" מבחינת ניקוד דמיון, הוא יכול לפעמים להסיק על קיום מידע רגיש מבלי לקבל אותו במפורש בתשובה. זו לא סכנה מעשית ברוב המערכות, אך במערכות בעלות רגישות קיצונית שווה להכיר את הסיכון התיאורטי הזה ולשקול rate limiting על שאילתות חוזרות מאותו משתמש כהגנה נוספת.

הרשאות דינמיות מבוססות הקשר: מעבר ל-ACL סטטי

מודל ACL מבוסס קבוצות, כפי שתואר למעלה, מכסה את רוב המקרים אך לא את כולם. יש מצבים שבהם ההרשאה לא נגזרת מקבוצה קבועה אלא מהקשר דינמי — למשל, נציג שירות לקוחות מורשה לראות פרטי לקוח רק בזמן שיש לו טיקט פתוח עבורו, או מנהל פרויקט מורשה לראות מסמכי תקציב רק לפרויקטים שהוא בפועל מנהל כרגע, רשימה שמשתנה מעת לעת. מודל כזה דורש גישת Attribute-Based Access Control (ABAC) במקום Role-Based פשוט: ההחלטה אם chunk נגיש למשתמש נגזרת מהצלבה בזמן אמת בין תכונות המשתמש (התפקיד שלו, הטיקטים הפתוחים שהוא מטפל בהם) לבין תכונות ה-chunk (איזה לקוח או פרויקט הוא מתאר), ולא מרשימת allowed_groups סטטית שנשמרה מראש על ה-chunk. הטמעת ABAC מלא ב-Pre-Filtering של Vector DB מורכבת יותר, כי הפילטר עצמו הופך לתלוי-הקשר ולא רק לתלוי-משתמש — לעיתים קרובות הפתרון המעשי הוא שכבת ביניים שממירה את ההקשר הדינמי (הטיקטים הפתוחים כרגע, הפרויקטים הפעילים) לרשימת group_ids זמנית בכל בקשה, ומזריקה אותה כפילטר, כך שהתשתית הבסיסית נשארת פשוטה גם כשהלוגיקה העסקית שמעליה מורכבת יותר.

הרשאות ברמת שדה בתוך אותו מסמך

מקרה מורכב יותר, שנתקלים בו לרוב רק בפרודקשן, הוא כשמסמך בודד מכיל שדות ברמות רגישות שונות — למשל חוזה מסחרי שבו סעיפי התנאים המסחריים כלליים אך סעיף התמורה הכספית רגיש יותר. פירוק ל-chunks ברמת פסקה עוזר כאן בפועל, כי הוא מאפשר להצמיד רמת רגישות שונה לכל chunk בנפרד ולא רק למסמך כולו — כך שסעיפים כלליים בחוזה יכולים להיות נגישים לצוות מכירות בעוד הסעיף הפיננסי נגיש רק לצוות משפטי וכספים. זו סיבה נוספת (מעבר לאיכות retrieval) לכך שכדאי להשקיע ב-chunking מודע-מבנה כפי שתואר במאמר על Knowledge Ingestion Pipelines — הוא לא רק משפר דיוק, אלא גם מאפשר גרנולריות בקרת גישה שאי אפשר להשיג ברמת מסמך שלם.

בדיקות אוטומטיות לדליפת מידע

בקרת גישה שלא נבדקת אוטומטית באופן שוטף היא בקרת גישה שסביר שתישבר בשקט אחרי שינוי קוד לא קשור. מומלץ לבנות סוויטת טסטים ייעודית — Red Team Suite — שכוללת משתמשי בדיקה עם פרופילי הרשאה שונים, ומריצה שאילתות שמנוסחות במיוחד כדי לנסות "לעקוף" את ההרשאות (למשל שאילתות עקיפות שלא מזכירות במפורש את המונח הרגיש אך עלולות עדיין להחזיר chunk רגיש דרך דמיון סמנטי עקיף). הרצת הסוויטה הזו כחלק מ-CI, בכל שינוי בשכבת ה-Retrieval, תופסת רגרסיות הרשאה הרבה לפני שהן מגיעות לפרודקשן — ולעיתים לפני שהן מגיעות בכלל לסביבת בדיקות שמישהו בודק ידנית.

מתי להשקיע במודל הרשאות מלא

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

סיכום

RAG Access Control דורש לחשוב על הרשאות כחלק מובנה מארכיטקטורת ה-Retrieval, לא כשכבה שמתווספת בסוף. Pre-Filtering מבוסס metadata, סנכרון הרשאות בזמן אמת, והגנת עומק ברמת post-generation — אלה שלושת הרכיבים שהופכים מערכת RAG מסיכון אבטחה פוטנציאלי לתשתית שאפשר לסמוך עליה גם עם מידע רגיש.

תגיות: RAG · Access Control · ACL · Data Security · Vector Database · Metadata Filtering · Enterprise AI

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