FixVibe

// docs / baas security / supabase rls scanner

סורק Supabase RLS: מציאת טבלאות עם row-level security חסר או שבור

Row-level security (RLS) הוא הדבר היחיד שניצב בין נתוני הלקוחות שלך לבין האינטרנט כשאתה משחרר אפליקציה מבוססת-Supabase. כלי קוד מבוססי-AI מייצרים קוד בצורת RLS שמתקמפל, נשלח לייצור, ודולף נתונים בשקט — טבלאות שנוצרו ללא הפעלת RLS, מדיניויות שקוראות אך לא מגבילות, פרדיקטים שמשווים עמודה לעצמה. המאמר הזה מראה מה סורק Supabase RLS יכול להוכיח מבחוץ, ארבע צורות ה-RLS השבור שמופיעות באפליקציות vibe-coded, ואיך לסרוק את ה-deployment שלך תוך פחות מדקה.

מה סריקת RLS חיצונית יכולה להוכיח

סריקת RLS פסיבית רצה מול נקודת הקצה של PostgREST ש-Supabase חושפת ב-https://[project].supabase.co/rest/v1/. היא משתמשת רק במפתח anon הניתן לפרסום — אותו מפתח שהדפדפן שלך משתמש בו — ובוחנת מטא-נתונים של רשימות טבלאות, קריאות אנונימיות וכתיבות אנונימיות. היא לעולם לא מתאמתת כמשתמש ולעולם לא נוגעת בהרשאות service-role. כל מה שהיא יכולה לעשות, גם תוקף לא-מאומת באינטרנט יכול לעשות.

מחוץ למסד הנתונים, סורק יכול לאשר את הבאים בביטחון גבוה:

  • RLS מושבת בטבלה. PostgREST מחזיר שורות עבור SELECT אנונימי כש-RLS כבוי או כשמדיניות מתירה זאת. שני המקרים הם ממצא.
  • תפקיד ה-anon יכול להציג רשימת טבלאות. GET /rest/v1/ עם מפתח anon מחזיר את סכמת ה-OpenAPI עבור כל טבלה שלתפקיד anon יש בה הרשאה כלשהי. אפליקציות שנוצרו על-ידי AI מעניקות לעתים קרובות USAGE על הסכמה ו-SELECT על כל טבלה, מה שחושף את מפת הסכמה המלאה אפילו כש-RLS שולל את הקריאות בפועל.
  • תפקיד ה-anon יכול לבצע INSERT. POST בוחן עם ניחוש של צורת העמודות יצליח אם ל-RLS אין מדיניות INSERT ששוללת אותו — אפילו אם SELECT נעול.
  • מפתח ה-service-role נמצא בחבילת הדפדפן. סמוך ל-RLS: אם סורק מוצא SUPABASE_SERVICE_ROLE_KEY או JWT כלשהו עם role: service_role בחבילת ה-JavaScript, ה-RLS חסר משמעות — מי שמחזיק במפתח הזה עוקף כל מדיניות.

מה סריקה חיצונית לא יכולה להוכיח

היה הוגן לגבי גבולות הסורק. סריקת RLS חיצונית לא יכולה לקרוא את טבלת pg_policies שלך, את קבצי המיגרציה שלך, או את הפרדיקט המדויק של מדיניות כלשהי. היא מסיקה מהתנהגות black-box, מה שאומר שלפעמים היא תדווח על ממצא שמתברר כנתונים ציבוריים מכוונים (טבלת ניוזלטר שיווקי, קטלוג מוצרים ציבורי). דוח FixVibe מסמן אלה כ-ביטחון בינוני כשהסורק לא יכול לפענח את הכוונה — בחן את שם הטבלה והחלט.

ארבע צורות ה-RLS השבור שכלי AI מייצרים

כשאתה מכוון את Cursor, Claude Code, Lovable או Bolt ל-Supabase, אותם ארבעה דפוסי RLS שבורים מופיעים על פני אלפי אפליקציות. כל אחד מהם עובר בדיקת טיפוסים, מתקמפל, ונשלח לייצור:

צורה 1: RLS שלא הופעל מעולם

מצב הכשל הנפוץ ביותר. המיגרציה יוצרת את הטבלה אבל המפתח (או כלי ה-AI) שוכח ALTER TABLE ... ENABLE ROW LEVEL SECURITY. PostgREST משרת בשמחה את כל הטבלה לכל מי שמחזיק במפתח anon. תיקון: ALTER TABLE public.[name] ENABLE ROW LEVEL SECURITY; ALTER TABLE public.[name] FORCE ROW LEVEL SECURITY;. FORCE אינו אופציונלי — בלעדיו, הבעלים של הטבלה (וכל תפקיד עם בעלות על טבלה) עוקף את ה-RLS.

sql
ALTER TABLE public.[name] ENABLE ROW LEVEL SECURITY;
ALTER TABLE public.[name] FORCE  ROW LEVEL SECURITY;

צורה 2: RLS מופעל, אין מדיניויות

כשל עדין יותר. RLS מופעל אבל לא נכתבו מדיניויות. ברירת המחדל ב-PostgreSQL היא שלילה, אז משתמשים מאומתים לא רואים כלום — והמפתח מוסיף USING (true) כדי שהאפליקציה תעבוד, מה שמתיר לכולם לקרוא הכל. תיקון: כתוב מדיניות שמצמצמת לפי auth.uid(): CREATE POLICY "select_own" ON public.[name] FOR SELECT USING (auth.uid() = user_id); ומדיניות INSERT/UPDATE/DELETE תואמת.

sql
CREATE POLICY "select_own"
  ON public.[name]
  FOR SELECT
  USING (auth.uid() = user_id);

צורה 3: מדיניות משווה עמודה לעצמה

A copy-paste artefact. The developer writes <code>USING (user_id = user_id)</code> — which is always true — instead of <code>USING (auth.uid() = user_id)</code>. Type-checks pass; the policy permits every row. <strong>Fix:</strong> always compare a column to a function call (<code>auth.uid()</code>, <code>auth.jwt()->>'org_id'</code>, etc.), never to itself or to a constant.

צורה 4: מדיניות על SELECT אך לא על INSERT/UPDATE

המפתח נועל קריאות אך שוכח כתיבות. מדיניויות RLS הן לפי פקודה. FOR SELECT מגן רק על קריאות; לקוח אנונימי עדיין יכול לבצע INSERT אם אין מדיניות ששוללת זאת. תיקון: כתוב מדיניות לכל פקודה, או השתמש ב-FOR ALL עם תניות USING ו-WITH CHECK מפורשות.

איך סורק Supabase RLS של FixVibe עובד

הבדיקה baas.supabase-rls רצה בשלושה שלבים, כל אחד עם רמות ביטחון מפורשות:

  1. שלב 1 — fingerprint. הסורק זוחל באפליקציה המותקנת, מנתח את חבילת ה-JavaScript שלה, ומחלץ את ה-URL של פרויקט ה-Supabase ואת מפתח ה-anon מתצורת ה-runtime. ללא ניחוש DNS, ללא brute force — הוא קורא את מה שהדפדפן קורא.
  2. שלב 2 — גילוי סכמה. GET /rest/v1/ בודד עם מפתח anon מחזיר את סכמת ה-OpenAPI עבור כל טבלה שתפקיד ה-anon יכול לראות. הסורק רושם שמות טבלאות אך לא קורא נתוני שורות בשלב הזה.
  3. שלב 3 — בחינות קריאה וכתיבה. עבור כל טבלה שהתגלתה, הסורק מנפיק SELECT אנונימי אחד עם limit=1. אם מוחזרות שורות, ה-RLS מתירני. הסורק עוצר שם — הוא לא מונה שורות, לא דפדף, לא משנה נתונים. בחינות INSERT מוגבלות מאחורי אימות בעלות על דומיין ו-opt-in מפורש; הן לעולם לא רצות מול מטרות לא-מאומתות.

כל ממצא נשלח עם ה-URL המדויק של הבקשה, סטטוס התגובה, צורת התגובה (header בלבד), ושם הטבלה. פרומפט ה-תיקון של ה-AI בתחתית הממצא הוא בלוק SQL להעתקה והדבקה שתריץ ב-SQL editor של Supabase.

מה לעשות כשהסורק מוצא משהו

כל ממצא RLS הוא חירום runtime. נקודות קצה ציבוריות של PostgREST נסרקות על-ידי תוקפים תוך דקות. סדר התיקון הוא מכאני:

  1. בצע audit לכל טבלה. הרץ SELECT schemaname, tablename, rowsecurity FROM pg_tables WHERE schemaname = 'public'; ב-SQL editor של Supabase. כל שורה עם rowsecurity = false היא בעיה.
  2. הפעל RLS על כל טבלה ציבורית. כברירת מחדל הפעל ENABLE ROW LEVEL SECURITY ו-FORCE ROW LEVEL SECURITY על כל טבלה שנוצרת — הפוך את זה לתבנית מיגרציה.
  3. כתוב מדיניויות פקודה אחר פקודה. אל תשתמש ב-FOR ALL USING (true). כתוב מדיניויות מפורשות עבור SELECT, INSERT, UPDATE, DELETE — כל אחת מצומצמת ל-auth.uid() או לעמודת org-id מתוך auth.jwt().
  4. אמת עם חשבון שני. הירשם כמשתמש אחר, נסה לקרוא רשומות של משתמש אחר ישירות דרך ה-REST API. אם התגובה היא 200, המדיניות שבורה.
  5. סרוק מחדש. אחרי החלת התיקון, הרץ סריקת FixVibe מחדש מול אותו URL. הממצא baas.supabase-rls אמור להיעלם.
sql
-- Audit every table for missing RLS. Run in the Supabase SQL editor.
SELECT schemaname, tablename, rowsecurity
FROM   pg_tables
WHERE  schemaname = 'public'
ORDER  BY rowsecurity, tablename;

איך זה משתווה לסורקים אחרים

רוב כלי ה-DAST הגנריים (Burp Suite, OWASP ZAP, Nessus) לא יודעים מה זה PostgREST. הם יזחלו באפליקציה שלך, יתעלמו מהנתיב /rest/v1/, וידווחו על דפי ה-HTML שהם כן מבינים. Snyk ו-Semgrep הם כלי ניתוח סטטי — הם מוצאים קבצי מיגרציה במאגר שלך עם קריאות RLS חסרות, אבל הם לא יכולים להוכיח שמסד הנתונים המותקן מוגדר שגוי. FixVibe יושב בפער: פסיבי, מודע ל-BaaS, ממוקד במה שתוקף לא-מאומת יכול להוכיח מה-URL הציבורי.

שאלות נפוצות

האם הסורק יקרא או ישנה את הנתונים שלי?

לא. סריקות פסיביות מנפיקות לכל היותר SELECT ... limit=1 אחד לכל טבלה שהתגלתה כדי לאשר אם RLS מתיר קריאות אנונימיות. הסורק רושם את צורת התגובה, לא את תוכן השורה. בחינות INSERT, UPDATE ו-DELETE מוגבלות מאחורי אימות בעלות על דומיין ולעולם לא רצות מול מטרות לא-מאומתות.

האם זה עובד אם פרויקט ה-Supabase שלי מושהה או על דומיין מותאם אישית?

פרויקטים מושהים מחזירים 503 על כל בקשה — הסורק מדווח על הפרויקט כלא-נגיש. דומיינים מותאמים אישית עובדים כל עוד האפליקציה המותקנת עדיין טוענת את ה-SDK של לקוח Supabase בדפדפן; הסורק מחלץ את ה-URL של הפרויקט מהחבילה ממילא.

מה אם מפתח ה-anon שלי מתחלף או מפתח ה-publishable שלי משתנה?

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

האם הסורק בודק את מודל מפתח ה-publishable החדש של Supabase (<code>sb_publishable_*</code>)?

כן. הזיהוי מכיר גם את JWTs של anon הישנים וגם את מפתחות sb_publishable_* החדשים ומתייחס אליהם זהה — שניהם מיועדים להיות ציבוריים ושניהם משאירים את ה-RLS כקו ההגנה היחיד.

צעדים הבאים

הרץ סריקת FixVibe חינמית מול URL הייצור שלך — הבדיקה baas.supabase-rls מופעלת בכל תוכנית כולל השכבה החינמית. לקריאה מעמיקה יותר על מה עוד יכול לדלוף מפרויקט Supabase, ראה מפתח Supabase service role חשוף ב-JavaScript ו-רשימת בדיקה לאבטחת דליי אחסון של Supabase. לתצוגה מקיפה על פני כל ספקי ה-BaaS, קרא סורק תצורות שגויות של BaaS.

// סרוק את משטח ה-baas שלך

מצא את הטבלה הפתוחה לפני שמישהו אחר עושה זאת.

הכנס URL ייצור. FixVibe מזהה את ספקי ה-BaaS שהאפליקציה שלך מתקשרת איתם, מבצע fingerprint לנקודות הקצה הציבוריות שלהם, ומדווח מה לקוח לא-מאומת יכול לקרוא או לכתוב. חינם, ללא התקנה, ללא כרטיס.

  • שכבת חינם — 3 סריקות בחודש, ללא כרטיס בהרשמה.
  • Fingerprinting פסיבי של BaaS — אין צורך באימות דומיין.
  • Supabase, Firebase, Clerk, Auth0, Appwrite ועוד.
  • פרומפטים של תיקון AI על כל ממצא — הדבק חזרה לתוך Cursor / Claude Code.
הרץ סריקת BaaS חינמית

אין צורך בהרשמה

סורק Supabase RLS: מציאת טבלאות עם row-level security חסר או שבור — Docs · FixVibe