// docs / baas security / supabase rls scanner
Supabase RLS սկաներ․ գտիր table-ներ, որոնք չունեն կամ ունեն կոտրված row-level security
Row-level security-ն (RLS) միակ բանն է, որ կանգնած է քո հաճախորդների տվյալների և համացանցի միջև, երբ դու թողարկում ես Supabase-ով աջակցվող հավելված։ AI-ի կոդավորման գործիքները գեներացնում են RLS-ի տեսք ունեցող կոդ, որ կոմպիլյացվում, թողարկվում և լուռ արտահոսում է տվյալները — table-ներ ստեղծված առանց RLS-ի միացման, policy-ներ, որ կարդում են, բայց երբեք չեն սահմանափակում, պրեդիկատներ, որ սյունակը համեմատում են ինքն իր հետ։ Այս հոդվածը ցույց է տալիս՝ ինչ կարող է ապացուցել Supabase RLS սկաները դրսից, vibe-coded հավելվածներում երևացող կոտրված-RLS-ի չորս ձևերը, և ինչպես սկանավորել քո սեփական deployment-ն ավելի քան մեկ րոպեի ընթացքում։
Ինչ կարող է ապացուցել արտաքին RLS սկանը
Պասիվ RLS սկանն աշխատում է PostgREST endpoint-ի դեմ, որը Supabase-ը բացում է https://[project].supabase.co/rest/v1/ հասցեում։ Այն օգտագործում է միայն հանրային anon բանալին — նույնը, որ քո զննարկիչն է օգտագործում — և ստուգում է table-ի մետատվյալների ցանկը, անանուն ընթերցումները և անանուն գրառումները։ Այն երբեք չի վավերացվում որպես օգտատեր և երբեք չի դիպչում service-role արտոնություններին։ Այն ամենը, ինչ կարող է անել, կարող է անել նաև համացանցում չհաստատված հարձակվողը։
Տվյալների բազայից դուրս՝ սկաները կարող է բարձր վստահությամբ հաստատել հետևյալը․
- RLS-ն անջատված է table-ի վրա։ PostgREST-ը տողեր է վերադարձնում անանուն
SELECT-ի համար, երբ RLS-ն անջատված է կամ երբ policy-ն թույլատրում է։ Երկու դեպքն էլ գտածո է։ - Անանուն դերը կարող է թվարկել table-ները։
GET /rest/v1/-ը anon բանալիով վերադարձնում է OpenAPI սխեմա յուրաքանչյուր table-ի համար, որի վրաanonդերն ունի որևէ արտոնություն։ AI-ով գեներացված հավելվածները հաճախ տալիս ենUSAGEսխեմայի վրա ևSELECTամեն table-ի վրա, ինչը բացահայտում է ամբողջ սխեման, նույնիսկ երբ RLS-ն արգելում է իրական ընթերցումները։ - Անանուն դերը կարող է insert անել։ Ստուգող
POST-ը՝ սյունակների ձևի ենթադրությամբ, կհաջողվի, եթե RLS-ը չունիINSERTարգելող policy — նույնիսկ եթեSELECT-ը փակ է։ - Service-role բանալին զննարկիչի bundle-ում է։ RLS-ին հարակից․ եթե սկաները գտնում է
SUPABASE_SERVICE_ROLE_KEYկամ որևէ JWT՝role: service_roleպարունակությամբ, JavaScript bundle-ում, RLS-ն իմաստ չունի — այդ բանալին պահողը շրջանցում է ցանկացած policy։
Ինչը չի կարող ապացուցել արտաքին սկանը
Ազնիվ եղիր սկաների սահմանների հետ։ Արտաքին RLS սկանը չի կարող կարդալ քո pg_policies table-ը, քո migration ֆայլերը կամ որևէ policy-ի ճշգրիտ պրեդիկատը։ Այն եզրակացնում է սև-արկղային վարքից, ինչը նշանակում է, որ երբեմն կհայտնի գտածո, որը պարզվի, որ դիտավորյալ հանրային տվյալ է (մարքեթինգային newsletter table, հանրային ապրանքների կատալոգ)։ FixVibe-ի հաշվետվությունը դրանք նշում է որպես միջին վստահության, երբ սկաները չի կարող պարզել դիտավորությունը — ստուգիր table-ի անունը և որոշիր։
AI գործիքների արտադրած կոտրված-RLS-ի չորս ձևերը
Երբ դու Cursor, Claude Code, Lovable կամ Bolt ուղղորդում ես Supabase-ի վրա, նույն չորս կոտրված-RLS նմուշները ի հայտ են գալիս հազարավոր հավելվածներում։ Ամեն մեկն անցնում է type-check-ը, կոմպիլյացվում և թողարկվում է․
Ձև 1․ RLS երբեք չմիացված
Ամենատարածված ձախողման ռեժիմը։ Migration-ը ստեղծում է table-ը, բայց ծրագրավորողը (կամ AI գործիքը) մոռանում է ALTER TABLE ... ENABLE ROW LEVEL SECURITY։ PostgREST-ը ուրախությամբ սպասարկում է ամբողջ table-ը anon բանալի ունեցող ցանկացածին։ Շտկում․ ALTER TABLE public.[name] ENABLE ROW LEVEL SECURITY; ALTER TABLE public.[name] FORCE ROW LEVEL SECURITY;։ FORCE-ը պարտադիր է — առանց դրա table-ի սեփականատերը (և սեփականության դեր ունեցող ցանկացած role) շրջանցում է RLS-ը։
ALTER TABLE public.[name] ENABLE ROW LEVEL SECURITY;
ALTER TABLE public.[name] FORCE ROW LEVEL SECURITY;Ձև 2․ RLS միացված, policy-ներ չկան
Ավելի նուրբ ձախողում։ RLS-ը միացված է, բայց policy-ներ գրված չեն։ PostgreSQL-ում լռելյայնը deny-ն է, ուստի վավերացված օգտատերերը ոչինչ չեն տեսնում — և ծրագրավորողն ավելացնում է USING (true), որ հավելվածն աշխատի, ինչը թույլ է տալիս բոլորին կարդալ ամեն ինչ։ Շտկում․ գրիր policy, որ սահմանափակում է auth.uid()-ով․ 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-ն սյունակը համեմատում է ինքն իր հետ
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-ի
Ծրագրավորողը փակում է ընթերցումները, բայց մոռանում գրառումները։ RLS policy-ները հրամանի մակարդակով են։ FOR SELECT-ը պաշտպանում է միայն ընթերցումները. անանուն հաճախորդը կարող է դեռ INSERT անել, եթե ոչ մի policy չի արգելում։ Շտկում․ գրիր policy յուրաքանչյուր հրամանի համար կամ օգտագործիր FOR ALL բացահայտ USING և WITH CHECK պայմաններով։
Ինչպես է աշխատում FixVibe-ի Supabase RLS սկաները
baas.supabase-rls ստուգումն աշխատում է երեք փուլով, յուրաքանչյուրը՝ բացահայտ վստահության մակարդակներով․
- Փուլ 1 — fingerprint։ Սկաները քայլում է թողարկված հավելվածով, վերլուծում նրա JavaScript bundle-ը և runtime կարգավորումից հանում Supabase project URL-ն ու anon բանալին։ Ոչ DNS-ի կռահում, ոչ brute force — այն կարդում է այն, ինչ զննարկիչն է կարդում։
- Փուլ 2 — սխեմայի հայտնաբերում։ Մեկ
GET /rest/v1/-ը anon բանալիով վերադարձնում է OpenAPI սխեմա յուրաքանչյուր table-ի համար, որ anon դերը կարող է տեսնել։ Սկաները գրառում է table-ի անունները, բայց այս փուլում չի կարդում տողերի տվյալները։ - Փուլ 3 — ընթերցման և գրառման ստուգումներ։ Յուրաքանչյուր հայտնաբերված table-ի համար սկաներն ուղարկում է մեկ անանուն
SELECTlimit=1-ով։ Եթե տողեր են վերադառնում, RLS-ը թույլտու է։ Սկաներն այնտեղ կանգ է առնում — այն չի թվարկում տողերը, չի էջագնում, չի փոփոխում տվյալները։ INSERT ստուգումները սահմանափակված են հաստատված տիրույթի սեփականությամբ և բացահայտ թույլտվությամբ. դրանք երբեք չեն աշխատում չհաստատված թիրախների դեմ։
Յուրաքանչյուր գտածո ուղեկցվում է ճշգրիտ հարցման URL-ով, պատասխանի կարգավիճակով, պատասխանի ձևով (միայն վերնագիր) և table-ի անունով։ AI fix prompt-ը գտածոյի ներքևում պատճենահան-տեղադրման SQL block է, որը գործարկում ես Supabase SQL editor-ում։
Ինչ անել, երբ սկաները ինչ-որ բան է գտնում
Յուրաքանչյուր RLS գտածո runtime արտակարգ իրավիճակ է։ Հանրային PostgREST endpoint-ները հարձակվողների կողմից սկանավորվում են րոպեների ընթացքում։ Շտկման հաջորդականությունը մեխանիկական է․
- Աուդիտ արա ամեն table-ը։ Գործարկիր
SELECT schemaname, tablename, rowsecurity FROM pg_tables WHERE schemaname = 'public';Supabase SQL editor-ում։ Ցանկացած տողrowsecurity = false-ով խնդիր է։ - Միացրու RLS-ը յուրաքանչյուր հանրային table-ի վրա։ Լռելյայն դարձրու
ENABLE ROW LEVEL SECURITYևFORCE ROW LEVEL SECURITYստեղծվող յուրաքանչյուր table-ի վրա — դարձրու դա migration template։ - Գրիր policy-ները հրաման-առ-հրաման։ Մի օգտագործիր
FOR ALL USING (true)։ Գրիր բացահայտ policy-ներ SELECT-ի, INSERT-ի, UPDATE-ի, DELETE-ի համար — ամեն մեկը սահմանվածauth.uid()-ով կամauth.jwt()-ից org-id սյունակով։ - Ստուգիր երկրորդ հաշվով։ Գրանցվիր որպես այլ օգտատեր, փորձիր կարդալ մեկ այլ օգտատիրոջ գրառումները REST API-ի միջոցով ուղղակիորեն։ Եթե պատասխանը
200է, policy-ն կոտրված է։ - Կրկին սկանավորիր։ Շտկումը կիրառելուց հետո կրկին գործարկիր FixVibe սկանը նույն URL-ի դեմ։
baas.supabase-rlsգտածոն պետք է մաքրվի։
-- 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-ը ստատիկ վերլուծության գործիքներ են — նրանք գտնում են migration ֆայլեր քո repo-ում՝ բացակայող RLS կանչերով, բայց չեն կարող ապացուցել, որ թողարկված տվյալների բազան սխալ կարգավորված է։ FixVibe-ը գտնվում է բացում․ պասիվ, BaaS-ի մասին տեղյակ, կենտրոնացած այն բանի վրա, ինչ չհաստատված հարձակվողը կարող է ապացուցել հանրային URL-ից։
Հաճախակի տրվող հարցեր
Կկարդա՞ կամ կփոփոխի՞ իմ տվյալները սկաները։
Ոչ։ Պասիվ սկանները ուղարկում են առավելագույնը մեկ SELECT ... limit=1 հայտնաբերված table-ի համար՝ հաստատելու, թե արդյոք RLS-ը թույլատրում է անանուն ընթերցումներ։ Սկաները գրառում է պատասխանի ձևը, ոչ թե տողի բովանդակությունը։ INSERT, UPDATE և DELETE ստուգումները սահմանափակված են հաստատված տիրույթի սեփականությամբ և երբեք չեն աշխատում չհաստատված թիրախների դեմ։
Կաշխատի՞ սա, եթե իմ Supabase նախագիծը դադարեցված է կամ հատուկ տիրույթում։
Դադարեցված նախագծերը վերադարձնում են 503 յուրաքանչյուր հարցման համար — սկաները հաշվետու է, որ նախագիծն անհասանելի է։ Հատուկ տիրույթներն աշխատում են, քանի դեռ թողարկված հավելվածը դեռ բեռնում է Supabase client SDK-ն զննարկիչում. սկաները հանում է project URL-ը bundle-ից ամեն դեպքում։
Իսկ եթե իմ anon բանալին պտտվում է կամ իմ հանրային բանալին փոխվում է։
Կրկին գործարկիր սկանը։ Սկաները ամեն գործարկման ժամանակ վերահանում է բանալին ընթացիկ bundle-ից։ Պտտումն անվավեր է դարձնում միայն նախորդ հաշվետվությունը, ոչ թե տվյալների բազայի policy-ի վիճակը։
Ստուգո՞ւմ է սկաները Supabase-ի նոր publishable-key մոդելը (<code>sb_publishable_*</code>)։
Այո։ Դետեկտորը ճանաչում է և՛ ժառանգային anon JWT-ները, և՛ ավելի նոր sb_publishable_* բանալիները ու դրանք վերաբերվում է նույնականորեն — երկուսն էլ նախատեսված են հանրային լինելու համար և երկուսն էլ թողնում են RLS-ը որպես պաշտպանության միակ գիծ։
Հաջորդ քայլեր
Գործարկիր անվճար FixVibe սկան քո production URL-ի դեմ — baas.supabase-rls ստուգումը միացված է բոլոր փաթեթներում՝ ներառյալ անվճարը։ Ավելի խորը կարդալու համար այն մասին, թե էլ ինչ կարող է արտահոսել Supabase նախագծից, տես Supabase service role key-ի բացահայտում JavaScript-ում և Supabase storage bucket-ի անվտանգության ստուգաթերթ։ Բոլոր BaaS մատակարարների միասնական տեսքի համար կարդա BaaS սխալ կարգավորման սկաներ։
