// docs / baas security / supabase rls scanner
Supabase RLS scanner፦ የጠፋ ወይም የተበላሸ row-level security ያላቸውን table-ዎች ይፈልጉ
Row-level security (RLS) Supabase-backed app በሚያሰማሩበት ጊዜ በደንበኞችዎ data እና internet መካከል የቆመ ብቸኛ ነገር ነው። AI coding tool-ዎች ይተረጎማል፣ ይሰማራል፣ እና data በዝምታ የሚያፈስ RLS-shaped code ይፈጥራሉ — RLS enable ሳይደረግ የተፈጠሩ table-ዎች፣ የሚያነቡ ግን ምንም የማይገድቡ policy-ዎች፣ column-ን ከራሱ ጋር የሚያነጻጽሩ predicate-ዎች። ይህ ጽሑፍ Supabase RLS scanner ከውጭ ምን ሊያረጋግጥ እንደሚችል፣ በvibe-coded app-ዎች ውስጥ የሚታዩትን አራቱን የተበላሸ-RLS ቅርጾች፣ እና የራስዎን deployment ከአንድ ደቂቃ ባነሰ ጊዜ ውስጥ እንዴት scan እንደሚያደርጉ ያሳያል።
ውጫዊ RLS scan ምን ሊያረጋግጥ ይችላል
Passive RLS scan Supabase በhttps://[project].supabase.co/rest/v1/ ላይ የሚያጋለጠው PostgREST endpoint ላይ ይሰራል። የሚጠቀመው publishable anon key — browser-ዎ የሚጠቀመውን ቁልፍ — ብቻ ሲሆን፣ ለtable-list metadata፣ anonymous reads እና anonymous writes ይመረምራል። እንደ user authenticate አያደርግም እና service-role privilege-ዎችን አይነካም። እሱ ሊያደርገው የሚችለውን ሁሉ፣ በinternet ላይ ያለ unauthenticated attacker ሊያደርገው ይችላል።
ከdatabase ውጭ scanner የሚከተሉትን በከፍተኛ ግምት ሊያረጋግጥ ይችላል፦
- RLS በtable ላይ disable ነው። RLS ጠፍቶ ሲሆን ወይም policy ሲፈቅድ PostgREST ለanonymous
SELECTrow-ዎችን ይመልሳል። ሁለቱም ጉዳዮች finding ናቸው። - Anonymous role table-ዎችን list ሊያደርግ ይችላል። በanon key ያለ
GET /rest/v1/anonrole ቢያንስ አንድ privilege ላለበት እያንዳንዱ table የOpenAPI schema ይመልሳል። AI-የተፈጠሩ app-ዎች ብዙውን ጊዜ schema ላይUSAGEእና በእያንዳንዱ table ላይSELECTይሰጣሉ፣ ይህም RLS ትክክለኛ ንባቦችን ቢከለክልም ሙሉ schema map ያጋልጣል። - Anonymous role insert ሊያደርግ ይችላል። በcolumn shape ግምት የሚደረግ
POSTprobe RLSINSERTን የሚከለክል policy ከሌለው —SELECTቢቆለፍም — ይሳካል። - Service-role key በbrowser bundle ውስጥ ነው። ከRLS አጠገብ፦ scanner በJavaScript bundle ውስጥ
SUPABASE_SERVICE_ROLE_KEYወይምrole: service_roleያለው ማንኛውም JWT ካገኘ፣ RLS ምንም አይነት ጥቅም የለውም — የዚያ key ባለቤት እያንዳንዱን policy ይዘላል።
ውጫዊ scan ምን ሊያረጋግጥ አይችልም
ስለscanner ድንበሮች ሐቀኛ ይሁኑ። ውጫዊ RLS scan የእርስዎን pg_policies table፣ migration file-ዎችዎን ወይም የማንኛውንም policy ትክክለኛ predicate ማንበብ አይችልም። ከblack-box ባህሪ ይገነዘባል፣ ይህም ማለት ሆን ተብሎ public data እንደሆነ የሚቆጠር (marketing newsletter table፣ public product catalog) ሆኖ ሊገኝ የሚችል finding አንዳንድ ጊዜ ያስታውቃል። የFixVibe report scanner intent-ን መለየት በማይችልበት ጊዜ እነዚህን medium confidence ብሎ ይምልክታል — የtable ስም ይገምግሙ እና ይወስኑ።
AI tool-ዎች የሚፈጥሩት አራቱ የተበላሸ-RLS ቅርጾች
Cursor፣ Claude Code፣ Lovable ወይም Bolt ወደ Supabase ሲጠቁሙ፣ በሺዎች በሚቆጠሩ app-ዎች ላይ ተመሳሳዩ አራት የተበላሹ-RLS pattern-ዎች ይታያሉ። እያንዳንዱ type-check ያልፋል፣ ይተረጎማል፣ ይሰማራል፦
ቅርጽ 1፦ RLS ጨርሶ enable አልተደረገም
በጣም የተለመደው የውድቀት ሁነት። Migration table ይፈጥራል ግን developer-ው (ወይም AI tool-ው) ALTER TABLE ... ENABLE ROW LEVEL SECURITYን ይረሳዋል። PostgREST ሙሉውን table anon key ላለው ሁሉ ይሰጣል። መፍትሄ፦ ALTER TABLE public.[name] ENABLE ROW LEVEL SECURITY; ALTER TABLE public.[name] FORCE ROW LEVEL SECURITY;። FORCE አማራጭ አይደለም — ያለ እሱ የtable owner (እና table ownership ያለው ማንኛውም role) RLS-ን ይዘላል።
ALTER TABLE public.[name] ENABLE ROW LEVEL SECURITY;
ALTER TABLE public.[name] FORCE ROW LEVEL SECURITY;ቅርጽ 2፦ RLS enable ተደርጓል፣ ፖሊሲ የለም
ይበልጥ ስውር ውድቀት። RLS enable ተደርጓል ግን policy አልተጻፈም። በPostgreSQL ነባሪ deny ነው፣ ስለዚህ authenticated user-ዎች ምንም አያዩም — እና developer app-ው እንዲሰራ USING (true) ይጨምራል፣ ይህም ሁሉም ሰው ሁሉንም እንዲያነብ ይፈቅዳል። መፍትሄ፦ በauth.uid() የተወሰነ policy ይጻፉ፦ CREATE POLICY "select_own" ON public.[name] FOR SELECT USING (auth.uid() = user_id); እና ተዛማጅ INSERT/UPDATE/DELETE policy።
CREATE POLICY "select_own"
ON public.[name]
FOR SELECT
USING (auth.uid() = user_id);ቅርጽ 3፦ Policy column-ን ከራሱ ጋር ያነጻጽራል
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፦ Policy በSELECT ላይ ግን በINSERT/UPDATE ላይ አይደለም
Developer-ው ንባቦችን ይቆልፋል ግን writing ይረሳዋል። RLS policy-ዎች በcommand-ናቸው። FOR SELECT ንባቦችን ብቻ ይጠብቃል፤ የሚከለክል policy ከሌለ anonymous client አሁንም INSERT ሊያደርግ ይችላል። መፍትሄ፦ በcommand-ናቸው policy ይጻፉ ወይም በግልጽ USING እና WITH CHECK clause ጋር FOR ALLን ይጠቀሙ።
የFixVibe Supabase RLS scanner እንዴት እንደሚሰራ
የbaas.supabase-rls check በሦስት ደረጃ ይሰራል፣ እያንዳንዱም ግልጽ confidence level አለው፦
- ደረጃ 1 — fingerprint። Scanner-ው የተሰማራውን app crawl ያደርጋል፣ JavaScript bundle-ውን parse ያደርጋል፣ እና ከruntime configuration የSupabase project URL እና anon key ያወጣል። DNS guessing የለም፣ brute force የለም — browser የሚያነበውን ያነባል።
- ደረጃ 2 — schema discovery። በanon key ያለ አንድ
GET /rest/v1/anon role ሊያይ ለሚችለው እያንዳንዱ table OpenAPI schema ይመልሳል። Scanner-ው የtable ስሞችን ይመዘግባል ግን በዚህ ደረጃ row data አያነብም። - ደረጃ 3 — read እና write probe-ዎች። ለእያንዳንዱ የተገኘ table፣ scanner-ው አንድ anonymous
SELECTበlimit=1ያስኪዳል። Row-ዎች ከተመለሱ፣ RLS permissive ነው። Scanner-ው እዚያ ያቆማል — row-ዎችን አያስደግምም፣ paginate አያደርግም፣ data አይቀየርም። INSERT probe-ዎች በተረጋገጠ domain ownership እና ግልጽ opt-in የተወሰኑ ናቸው፤ በፍጹም ባልተረጋገጡ target-ዎች ላይ አይሰሩም።
እያንዳንዱ finding ከትክክለኛው request URL፣ response status፣ response shape (header-only) እና የtable ስም ጋር ይመጣል። የfinding ግርጌ ላይ ያለው AI fix prompt በSupabase SQL editor ውስጥ የሚሮጥ copy-paste SQL block ነው።
Scanner ነገር ሲያገኝ ምን ማድረግ አለበት
እያንዳንዱ RLS finding የruntime አደጋ ነው። Public PostgREST endpoint-ዎች በደቂቃዎች ውስጥ በattacker-ዎች ይscan ይደረጋሉ። የremediation ቅደም ተከተል mechanical ነው፦
- እያንዳንዱን table audit ያድርጉ። በSupabase SQL editor ውስጥ
SELECT schemaname, tablename, rowsecurity FROM pg_tables WHERE schemaname = 'public';ያስኪዱ።rowsecurity = falseያለው ማንኛውም row ችግር ነው። - በእያንዳንዱ public table ላይ RLS enable ያድርጉ። በሚፈጠረው እያንዳንዱ table ላይ
ENABLE ROW LEVEL SECURITYእናFORCE ROW LEVEL SECURITYን ነባሪ ያድርጉ — እንደ migration template ይያዙት። - Policy-ዎችን በcommand-by-command ይጻፉ።
FOR ALL USING (true)ን አይጠቀሙ። ለSELECT፣ INSERT፣ UPDATE፣ DELETE ግልጽ policy-ዎች ይጻፉ — እያንዳንዱ በauth.uid()ወይም ከauth.jwt()በመጣ org-id column የተወሰነ። - በሁለተኛ account ያረጋግጡ። እንደ ሌላ user ይመዝገቡ፣ በREST API በቀጥታ የሌላ user-ን record ለማንበብ ይሞክሩ። Response
200ከሆነ፣ policy የተበላሸ ነው። - እንደገና scan ያድርጉ። Fix-ውን ከተግባራዊ ካደረጉ በኋላ፣ በተመሳሳዩ URL ላይ FixVibe scan እንደገና ያስኪዱ። የ
baas.supabase-rlsfinding መጥፋት አለበት።
-- 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;ይህ ከሌሎች scanner-ዎች ጋር እንዴት ይነጻጸራል
አብዛኞቹ generic DAST tool-ዎች (Burp Suite፣ OWASP ZAP፣ Nessus) PostgREST ምን እንደሆነ አያውቁም። App-ዎን crawl ያደርጋሉ፣ የ/rest/v1/ path-ን ይዘላሉ፣ እና በሚገነዘቡት HTML page-ዎች ላይ ይዘግባሉ። Snyk እና Semgrep static-analysis tool-ዎች ናቸው — በrepo-ዎ ውስጥ የጠፉ RLS call-ዎች ያላቸውን migration file-ዎች ይፈልጋሉ ግን የተሰማራው database misconfigured መሆኑን ማረጋገጥ አይችሉም። FixVibe በዚህ ክፍተት ውስጥ ይቀመጣል፦ passive፣ BaaS-aware፣ unauthenticated attacker ከpublic URL ሊያረጋግጥ የሚችለውን ላይ ያተኮረ።
ብዙ ጊዜ የሚጠየቁ ጥያቄዎች
Scanner data-ዬን ያነባል ወይም ይቀይራል?
አይ። Passive scan-ዎች RLS anonymous read መፍቀዱን ለማረጋገጥ በተገኘ table ቢበዛ አንድ SELECT ... limit=1 ያስኪዳሉ። Scanner-ው response shape-ን ይመዘግባል፣ የrow ይዘት አይደለም። INSERT፣ UPDATE እና DELETE probe-ዎች በተረጋገጠ domain ownership የተወሰኑ ሲሆኑ በፍጹም ባልተረጋገጡ target-ዎች ላይ አይሰሩም።
የSupabase project-ዬ paused ከሆነ ወይም custom domain ላይ ከሆነ ይሰራል?
Paused project-ዎች በእያንዳንዱ request 503 ይመልሳሉ — scanner-ው project-ውን እንደማይደረስ ይዘግባል። Custom domain-ዎች የተሰማራው app በbrowser ውስጥ የSupabase client SDK መጫን እስከቀጠለ ይሰራሉ፤ scanner-ው ምን አይነት ቢሆን ከbundle የproject URL ያወጣል።
Anon key ከተለወጠ ወይም publishable key ከተቀየረስ?
Scan-ውን እንደገና ያስኪዱ። Scanner-ው በእያንዳንዱ run ላይ key-ውን ከአሁኑ bundle እንደገና ያወጣል። ሮቴሽን ቀደም ያለውን report ብቻ ይሰርዛል፣ የdatabase policy state-ን አይደለም።
Scanner አዲሱን የSupabase publishable-key ሞዴል (<code>sb_publishable_*</code>) ይፈትሻል?
አዎ። Detector ሁለቱንም legacy anon JWT-ዎች እና አዲሶቹን sb_publishable_* key-ዎች ይገነዘባል እና በተመሳሳይ ይይዛቸዋል — ሁለቱም public እንዲሆኑ የተደረጉ ናቸው፣ ሁለቱም RLS-ን እንደ ብቸኛ የመከላከያ መስመር ይተዋሉ።
ቀጣይ እርምጃዎች
በproduction URL-ዎ ላይ ነጻ FixVibe scan ያስኪዱ — የbaas.supabase-rls check ነጻ tier ጨምሮ በእያንዳንዱ plan ላይ enable ነው። ከSupabase project ሌላ ምን ሊፈስ እንደሚችል ጥልቅ ለማንበብ Supabase service role key in JavaScript የተጋለጠ እና የSupabase storage bucket security checklist ይመልከቱ። በሁሉም BaaS provider-ዎች ላይ ለሚሰፋ እይታ፣ BaaS misconfiguration scannerን ያንብቡ።
