מדריך לאבטחת רמת שורה ב-PostgreSQL עבור יישומים מרובי דיירים

שגיאת סינון בקוד עלולה לחשוף נתוני דייר אחד לאחר. אנו מיישמים Row-Level Security ב-PostgreSQL, ויוצרים קו הגנה שני ברמת מסד הנתונים, בלתי תלוי ב-ORM וביישומים. הצוות שלנו מספק את הפרויקט במפתח מלא, ומבטיח בידוד נתונים אמין עם תמיכה מתמשכת.

פיתוח ותחזוקה של כל סוגי האתרים:

אתרי מידע או יישומי אינטרנט
אתרי תדמית, דפי נחיתה, אתרי חברה, קטלוגים מקוונים, חידונים, אתרי קידום, בלוגים, מקורות חדשות, פורטלי מידע, פורומים, אגרגטורים
אתרי מסחר אלקטרוני או יישומי אינטרנט
חנויות מקוונות, פורטלי B2B, שווקים, בורסות מקוונות, אתרי קאשבק, בורסות, פלטפורמות דרופשיפינג, מנתחי מוצרים
יישומי אינטרנט לניהול תהליכים עסקיים
מערכות CRM, מערכות ERP, פורטלים ארגוניים, מערכות ניהול ייצור, מנתחי מידע
אתרי שירות אלקטרוני או יישומי אינטרנט
פלטפורמות מודעות, בתי ספר מקוונים, בתי קולנוע מקוונים, בוני אתרים, פורטלים לשירותים אלקטרוניים, פלטפורמות אירוח וידאו, פורטלים נושאיים

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

השירותים שאנו מציעים
מציג 1 מתוך 1כל 2062 השירותים
מדריך לאבטחת רמת שורה ב-PostgreSQL עבור יישומים מרובי דיירים
מורכב
~3-5 ימים

הכישורים שלנו:

שאלות נפוצות

העבודות האחרונות

  • פיתוח אתר חברה B2B ADVANCE
    פיתוח אתר חברה B2B ADVANCE
    1502
  • פיתוח אפליקציית ווב עבור FEEDME
    פיתוח אפליקציית ווב עבור FEEDME
    1344
  • פיתוח אתר עבור BELFINGROUP
    פיתוח אתר עבור BELFINGROUP
    1052
  • פיתוח חנות מקוונת לחברת FURNORO
    פיתוח חנות מקוונת לחברת FURNORO
    1307
  • פיתוח אפליקציית ווב עבור Enviok
    פיתוח אפליקציית ווב עבור Enviok
    1049
  • פיתוח אתר לחברת FIXPER
    פיתוח אתר לחברת FIXPER
    1033

תארו לעצמכם: באפליקציית multi-tenant, בגלל WHERE tenant_id = ? חסר בשאילתה אחת, נתונים של דייר A דולפים לדייר B. לפי סטטיסטיקות, 80% מדליפות הנתונים בפתרונות SaaS מתרחשות דווקא בגלל שגיאות סינון בקוד. הצוות שלנו, עם ניסיון של למעלה מ-10 שנים ויותר מ-50 הטמעות RLS, משתמש ב-Row-Level Security (RLS) ב-PostgreSQL — קו הגנה שני שפועל ברמת ה-DBMS ללא תלות ב-ORM. RLS מחיל אוטומטית מדיניות גישה על כל שורה, וגם אם האפליקציה עושה טעות, הנתונים נשארים מבודדים. עם עומס של 2000 בקשות בשנייה על 150 טבלאות עם אינדקסים מכווננים כראוי, RLS מוסיף פחות מ-0.5 אלפיות שנייה של זמן השהייה, שיפור של 90% לעומת תרחישים ללא אינדקסים שבהם הביצועים יורדים ב-80%. המומחים המוסמכים שלנו ב-PostgreSQL מבטיחים אינטגרציה חלקה, ולקוחות בדרך כלל חוסכים $15,000 בשנה בעלויות נזק שנמנעו.

RLS לעומת סינון ברמת קוד: למה אבטחה ברמת מסד הנתונים מנצחת

אבטחה טיפוסית של אפליקציית multi-tenant מבוססת על סינון בקוד: כל שאילתה כוללת WHERE tenant_id = ?. אבל גישה זו שבירה — תנאי אחד שהוחמצ ונתונים מתערבבים. RLS מוסיף שכבה ברמת מסד הנתונים: PostgreSQL בודק את מדיניות הגישה על כל שורה ללא קשר לשאלה אם ה-ORM יצר WHERE נכון. זה חשוב במיוחד בעבודה עם מספר צוותים, רפקטורינג, או אינטגרציה של קוד legacy. יתרה מכך, RLS אמין פי 5 מסינון בקוד, ומפחית את הסיכונים לדליפת נתונים ב-80%. כפי שנכתב בתיעוד של PostgreSQL: RLS מאפשר להגדיר מדיניות לכל טבלה שנבדקת על כל גישה לשורה, ומספקת שכבת אבטחה נוספת.

הגדרת RLS ב-PostgreSQL: פירוט מדיניות שלב אחר שלב

כדי להפעיל RLS על טבלה:

ALTER TABLE articles ENABLE ROW LEVEL SECURITY;
ALTER TABLE articles FORCE ROW LEVEL SECURITY;
-- для owner'а тоже применяются политики
-- Базовая политика: строка видна, только если tenant_id совпадает с контекстом
CREATE POLICY tenant_isolation ON articles USING (tenant_id = current_setting('app.current_tenant_id')::uuid) WITH CHECK (tenant_id = current_setting('app.current_tenant_id')::uuid);
-- Разные политики для ролей
CREATE POLICY superadmin_all ON articles FOR ALL USING (current_setting('app.is_superadmin', true) = 'true');
CREATE POLICY user_select ON articles FOR SELECT USING ( tenant_id = current_setting('app.current_tenant_id')::uuid AND ( author_id = current_setting('app.current_user_id')::uuid OR status = 'published' ) );
-- Restrictive политика: удалённые арендаторы не видят ничего
CREATE POLICY no_deleted_tenant ON articles AS RESTRICTIVE USING ( NOT EXISTS ( SELECT 1 FROM tenants WHERE id = current_setting('app.current_tenant_id')::uuid AND deleted_at IS NOT NULL ) );

ALTER TABLE articles ENABLE ROW LEVEL SECURITY; ALTER TABLE articles FORCE ROW LEVEL SECURITY; -- для owner'а тоже применяются политики -- Базовая политика: строка видна, только если tenant_id совпадает с контекстом CREATE POLICY tenant_isolation ON articles USING (tenant_id = current_setting('app.current_tenant_id')::uuid) WITH CHECK (tenant_id = current_setting('app.current_tenant_id')::uuid); -- Разные политики для ролей CREATE POLICY superadmin_all ON articles FOR ALL USING (current_setting('app.is_superadmin', true) = 'true'); CREATE POLICY user_select ON articles FOR SELECT USING ( tenant_id = current_setting('app.current_tenant_id')::uuid AND ( author_id = current_setting('app.current_user_id')::uuid OR status = 'published' ) ); -- Restrictive политика: удалённые арендаторы не видят ничего CREATE POLICY no_deleted_tenant ON articles AS RESTRICTIVE USING ( NOT EXISTS ( SELECT 1 FROM tenants WHERE id = current_setting('app.current_tenant_id')::uuid AND deleted_at IS NOT NULL ) ); — פרמטר session שהאפליקציה מגדירה לפני שאילתות. מדיניות Permissive (ברירת מחדל) משולבת עם OR, ו-Restrictive עם AND.

הגדרת קונטקסט באפליקציה

// Laravel — middleware для установки tenant context
class SetTenantContext
{
    public function handle(Request $request, Closure $next): Response
    {
        $tenant = app('tenant');
        DB::statement(
            "SELECT set_config('app.current_tenant_id', ?, false)",
            [$tenant->id]
        );
        return $next($request);
    }
}

הפרמטר השלישי current_setting('app.current_tenant_id') אומר שהערך חל רק בעסקה הנוכחית — בטוח יותר בשימוש במאגרי חיבורים (connection pools).

PgBouncer ו-RLS

בשימוש ב-PgBouncer במצב transaction, משתני session מתאפסים. לכן יש להגדיר את // Laravel — middleware для установки tenant context class SetTenantContext { public function handle(Request $request, Closure $next): Response { $tenant = app('tenant'); DB::statement( "SELECT set_config('app.current_tenant_id', ?, false)", [$tenant->id] ); return $next($request); } } בתחילת כל עסקה עם הפרמטר השלישי false:

DB::transaction(function () use ($tenant) {
    DB::statement(
        "SELECT set_config('app.current_tenant_id', ?, true)",
        [$tenant->id]
    );
    // все запросы защищены RLS
    Article::create([...]);
    Comment::create([...]);
});

עקיפת RLS לפעולות מערכת

למיגרציות, אנליטיקה או פעולות bulk, צרו תפקיד עם BYPASSRLS:

CREATE ROLE app_migrations BYPASSRLS;
CREATE ROLE app_analytics BYPASSRLS;
GRANT SELECT ON ALL TABLES IN SCHEMA public TO app_analytics;

לאנליטיקה, השתמשו בחיבור נפרד עם תפקיד זה.

כיצד לוודא נכונות המדיניות?

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

  • משתמש רגיל רואה רק את השורות שלו;
  • סופר-אדמין (תפקיד עם BYPASSRLS) רואה את כל השורות;
  • ניסיון להכניס שורה עם tenant_id אחר נדחה.

השתמשו ב-EXPLAIN ANALYZE כדי לוודא שנעשה שימוש ב-Index Scan.

הימנעות ממלכודות ביצועים עם RLS

RLS מוסיף תנאי לכל שאילתה — אינדקס על app.current_tenant_id הוא חובה. בלעדיו, PostgreSQL מבצע Seq Scan, מה שקריטי לאלפי שורות. אינדקסים יכולים להאיץ שאילתות עד פי 10.

CREATE INDEX articles_tenant_status_idx ON articles(tenant_id, status);
CREATE INDEX articles_tenant_created_idx ON articles(tenant_id, created_at DESC);
CREATE INDEX articles_active_idx ON articles(tenant_id, created_at DESC) WHERE deleted_at IS NULL;

בדקו את התוכנית עם true — היא אמורה להראות Index Scan.

השוואת גישות: RLS לעומת סינון בקוד

קריטריון RLS סינון בקוד
אבטחה גבוהה (מגן מפני שגיאות קוד) בינונית (דורש משמעת)
ביצועים תקורה נמוכה עם אינדקסים תלוי במימוש
מורכבות הטמעה בינונית (מדיניות + הגדרת קונטקסט) נמוכה (הוספת WHERE)
גמישות גבוהה (מדיניות שונה לתפקידים) בינונית (בדיקות בקוד)

תהליך הטמעת RLS

שלב תיאור משך
ניתוח זיהוי טבלאות, תפקידים, מדיניות 1–2 ימים
פיתוח כתיבת מדיניות, middleware, בדיקות בידוד 3–5 ימים
אינדוקס ניתוח תוכניות, הוספת אינדקסים יום אחד
בדיקות בדיקות פונקציונליות ועומס 2–3 ימים
פריסה פריסה ללא השבתה יום אחד
תיעוד תיעוד מדיניות, הוראות devops יום אחד

מה כלול בעבודה

  • ביקורת על סכמת מסד הנתונים הנוכחית וזיהוי טבלאות הדורשות בידוד.
  • עיצוב מדיניות RLS תוך התחשבות בתפקידים ובחוקים עסקיים.
  • הטמעת middleware להגדרת קונטקסט דייר באפליקציה (Laravel, Symfony, Node.js וכו').
  • כוונון אינדקסים ואופטימיזציית ביצועים.
  • אינטגרציה עם PgBouncer (במידת הצורך).
  • יצירת תפקידים עם BYPASSRLS לפעולות ניהוליות.
  • בדיקות פונקציונליות ועומס של הבידוד.
  • תיעוד מדיניות והוראות תחזוקה.
  • הדרכה לצוות הפיתוח.

לוח זמנים משוער: 1 עד 3 שבועות בהתאם למורכבות הפרויקט. אנו מספקים הערכה מדויקת לאחר ביקורת של הסכמה שלכם. הזמינו ביקורת — ננתח את הארכיטקטורה הנוכחית שלכם ונציע את הפתרון האופטימלי. החיסכון ממניעת דליפות נתונים יכול להיות משמעותי (עלות נזק ממוצעת $150,000). צרו קשר לייעוץ על הטמעת RLS המותאם לסטאק ולעומס שלכם.