// docs / baas security / supabase rls scanner
Supabase RLS scanner: অনুপস্থিত বা ভাঙা row-level security সহ tables খুঁজুন
Row-level security (RLS) হল একমাত্র জিনিস যা আপনি একটি Supabase-সমর্থিত অ্যাপ ship করার সময় আপনার গ্রাহকদের ডেটা এবং ইন্টারনেটের মধ্যে দাঁড়িয়ে থাকে। AI কোডিং টুলগুলি এমন RLS-আকৃতির কোড তৈরি করে যা compile হয়, ship হয়, এবং নীরবে ডেটা leak করে — RLS enable না করে তৈরি tables, যে policies পড়ে কিন্তু কখনো সীমাবদ্ধ করে না, যে predicates একটি column-কে নিজের সাথে তুলনা করে। এই প্রবন্ধটি দেখায় একটি Supabase RLS scanner বাইরে থেকে কী প্রমাণ করতে পারে, vibe-coded অ্যাপগুলিতে দেখা চারটি ভাঙা-RLS আকার, এবং এক মিনিটের কম সময়ে আপনার নিজস্ব deployment কীভাবে scan করবেন।
একটি বাহ্যিক RLS scan কী প্রমাণ করতে পারে
একটি passive RLS scan Supabase যে PostgREST endpoint-কে https://[project].supabase.co/rest/v1/-এ expose করে তার বিরুদ্ধে চলে। এটি কেবলমাত্র publishable anon key ব্যবহার করে — সেই একই key যা আপনার browser ব্যবহার করে — এবং table-list metadata, anonymous reads, এবং anonymous writes-এর জন্য probe করে। এটি কখনোই একজন user হিসাবে authenticate করে না এবং service-role privileges-কে কখনো স্পর্শ করে না। এটি যা কিছু করতে পারে, ইন্টারনেটে একজন unauthenticated আক্রমণকারীও তা করতে পারে।
database-এর বাইরে থেকে, একটি scanner উচ্চ আত্মবিশ্বাসের সাথে নিম্নলিখিতগুলি confirm করতে পারে:
- একটি table-এ RLS disabled আছে। PostgREST একটি anonymous
SELECT-এর জন্য rows return করে যখন RLS বন্ধ থাকে বা যখন কোনো policy এটি অনুমতি দেয়। উভয় ক্ষেত্রেই একটি finding। - Anonymous role tables list করতে পারে। anon key সহ একটি
GET /rest/v1/প্রতিটি table-এর জন্য OpenAPI schema return করে যেগুলিতেanonrole-এর কোনো privilege আছে। AI-generated অ্যাপগুলি প্রায়ই schema-তেUSAGEএবং প্রতিটি table-এSELECTgrant করে, যা প্রকৃত reads-কে RLS deny করার সময়ও সম্পূর্ণ schema map প্রকাশ করে দেয়। - Anonymous role insert করতে পারে। column shape-এর অনুমান সহ একটি probing
POSTসফল হবে যদি RLS-এর কাছে এটি deny করার কোনোINSERTpolicy না থাকে — এমনকিSELECTlocked down হলেও। - Service-role key browser bundle-এ আছে। RLS-এর সংলগ্ন: যদি scanner JavaScript bundle-এ
SUPABASE_SERVICE_ROLE_KEYবাrole: service_roleসহ কোনো JWT খুঁজে পায়, তাহলে RLS অর্থহীন — সেই key-এর ধারক প্রতিটি policy bypass করে।
একটি বাহ্যিক scan কী প্রমাণ করতে পারে না
scanner-এর সীমাবদ্ধতা সম্পর্কে সৎ থাকুন। একটি বাহ্যিক RLS scan আপনার pg_policies table, আপনার migration files, বা কোনো policy-এর সঠিক predicate পড়তে পারে না। এটি black-box behaviour থেকে অনুমান করে, যার অর্থ এটি কখনো কখনো এমন একটি finding রিপোর্ট করবে যা আসলে ইচ্ছাকৃত public data (একটি marketing newsletter table, একটি public product catalog)। যখন scanner intent স্পষ্ট করতে পারে না তখন FixVibe report এগুলিকে medium confidence হিসাবে flag করে — table নাম পর্যালোচনা করুন এবং সিদ্ধান্ত নিন।
AI টুলগুলি যে চারটি ভাঙা-RLS আকার তৈরি করে
যখন আপনি Cursor, Claude Code, Lovable, বা Bolt-কে Supabase-এর দিকে নির্দেশ করেন, তখন হাজার হাজার অ্যাপে একই চারটি ভাঙা-RLS pattern উদিত হয়। প্রতিটি type-check পাস করে, compile হয়, এবং ship হয়:
আকার 1: RLS কখনো enable হয়নি
সবচেয়ে সাধারণ failure mode। Migration table তৈরি করে কিন্তু developer (বা AI টুল) ALTER TABLE ... ENABLE ROW LEVEL SECURITY ভুলে যায়। PostgREST anon key সহ যে কাউকে সমগ্র table আনন্দের সাথে serve করে। সমাধান: ALTER TABLE public.[name] ENABLE ROW LEVEL SECURITY; ALTER TABLE public.[name] FORCE ROW LEVEL SECURITY;। FORCE non-optional — এটি ছাড়া table owner (এবং table ownership সহ যেকোনো role) RLS bypass করে।
ALTER TABLE public.[name] ENABLE ROW LEVEL SECURITY;
ALTER TABLE public.[name] FORCE ROW LEVEL SECURITY;আকার 2: RLS enabled, কোনো policies নেই
একটি আরও সূক্ষ্ম failure। RLS enabled কিন্তু কোনো policies লেখা হয়নি। PostgreSQL-এ default হল deny, তাই authenticated users কিছুই দেখে না — এবং developer অ্যাপ কাজ করানোর জন্য USING (true) যোগ করে, যা সবাইকে সবকিছু পড়ার অনুমতি দেয়। সমাধান: এমন একটি policy লিখুন যা auth.uid() দ্বারা scoped হয়: 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: SELECT-এ Policy কিন্তু INSERT/UPDATE-এ নয়
Developer reads locked down করে কিন্তু writes ভুলে যায়। RLS policies per-command। FOR SELECT শুধুমাত্র reads সুরক্ষিত করে; কোনো policy deny না করলে একটি anonymous client এখনো INSERT করতে পারে। সমাধান: per command একটি policy লিখুন, বা স্পষ্ট USING এবং WITH CHECK clauses সহ FOR ALL ব্যবহার করুন।
FixVibe Supabase RLS scanner কীভাবে কাজ করে
baas.supabase-rls check তিনটি stage-এ চলে, প্রতিটি স্পষ্ট confidence levels সহ:
- Stage 1 — fingerprint। Scanner deployed অ্যাপ crawl করে, এর JavaScript bundle parse করে, এবং runtime configuration থেকে Supabase project URL এবং anon key বের করে আনে। কোনো DNS অনুমান নেই, কোনো brute force নেই — এটি যা browser পড়ে তাই পড়ে।
- Stage 2 — schema discovery। anon key সহ একটি একক
GET /rest/v1/প্রতিটি table-এর জন্য OpenAPI schema return করে যা anon role দেখতে পারে। Scanner table নামগুলি record করে কিন্তু এই stage-এ row data পড়ে না। - Stage 3 — read এবং write probes। প্রতিটি আবিষ্কৃত table-এর জন্য, scanner
limit=1সহ একটি anonymousSELECTissue করে। যদি rows return হয়, তাহলে RLS permissive। Scanner সেখানেই থামে — এটি rows enumerate করে না, paginate করে না, ডেটা modify করে না। INSERT probes verified domain ownership এবং স্পষ্ট opt-in-এর পিছনে gated; এগুলি কখনো unverified targets-এর বিরুদ্ধে fire হয় না।
প্রতিটি finding সঠিক request URL, response status, response shape (header-only), এবং table নাম সহ ship হয়। Finding-এর নিচে AI fix prompt একটি copy-paste SQL block যা আপনি Supabase SQL editor-এ চালান।
scanner কিছু খুঁজে পেলে কী করবেন
প্রতিটি RLS finding একটি runtime emergency। Public PostgREST endpoints-গুলি আক্রমণকারীদের দ্বারা মিনিটের মধ্যে scan হয়ে যায়। Remediation sequence যান্ত্রিক:
- প্রতিটি 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 SECURITYdefault করুন — এটি একটি migration template বানান। - Policies command-by-command লিখুন।
FOR ALL USING (true)ব্যবহার করবেন না। SELECT, INSERT, UPDATE, DELETE-এর জন্য স্পষ্ট policies লিখুন — প্রতিটিauth.uid()বাauth.jwt()থেকে একটি org-id column-এ scoped। - একটি দ্বিতীয় account দিয়ে verify করুন। একটি ভিন্ন user হিসাবে sign up করুন, সরাসরি REST API-এর মাধ্যমে অন্য user-এর records পড়ার চেষ্টা করুন। যদি response
200হয়, তাহলে policy ভাঙা। - আবার scan করুন। Fix প্রয়োগ করার পরে, একই URL-এর বিরুদ্ধে একটি FixVibe scan পুনরায় চালান।
baas.supabase-rlsfinding clear হওয়া উচিত।
-- 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;এটি অন্যান্য scanners-এর সাথে কীভাবে তুলনা করে
অধিকাংশ generic DAST টুল (Burp Suite, OWASP ZAP, Nessus) PostgREST কী তা জানে না। তারা আপনার অ্যাপ crawl করবে, /rest/v1/ path উপেক্ষা করবে, এবং তারা যে HTML pages বোঝে সেগুলির উপর রিপোর্ট করবে। Snyk এবং Semgrep static-analysis টুল — তারা অনুপস্থিত RLS calls সহ আপনার repo-তে migration files খুঁজে পায়, কিন্তু তারা প্রমাণ করতে পারে না যে deployed database misconfigured। FixVibe এই ফাঁকে বসে: passive, BaaS-aware, এক unauthenticated আক্রমণকারী public URL থেকে কী প্রমাণ করতে পারে তার উপর কেন্দ্রীভূত।
প্রায়শই জিজ্ঞাসিত প্রশ্ন
scanner কি আমার ডেটা পড়বে বা modify করবে?
না। Passive scans প্রতিটি আবিষ্কৃত table-এর জন্য সর্বাধিক একটি SELECT ... limit=1 issue করে confirm করতে যে RLS anonymous reads-এর অনুমতি দেয় কিনা। Scanner response shape record করে, row contents নয়। INSERT, UPDATE, এবং DELETE probes verified domain ownership-এর পিছনে gated এবং কখনো unverified targets-এর বিরুদ্ধে চলে না।
এটি কি কাজ করে যদি আমার Supabase project paused থাকে বা একটি custom domain-এ থাকে?
Paused projects প্রতিটি request-এ 503 return করে — scanner project-কে unreachable হিসাবে রিপোর্ট করে। Custom domains কাজ করে যতক্ষণ deployed অ্যাপ এখনো browser-এ Supabase client SDK লোড করে; scanner যেকোনোভাবেই bundle থেকে project URL বের করে।
আমার anon key rotate হলে বা আমার publishable key পরিবর্তন হলে কী হবে?
Scan পুনরায় চালান। Scanner প্রতিটি run-এ current bundle থেকে key পুনরায় বের করে। Rotation শুধুমাত্র পূর্ববর্তী report invalidate করে, database-এর policy state নয়।
scanner কি নতুন Supabase publishable-key model (<code>sb_publishable_*</code>) check করে?
হ্যাঁ। Detector legacy anon JWTs এবং নতুন sb_publishable_* keys উভয়কেই চিনতে পারে এবং একইভাবে treat করে — উভয়ই public হওয়ার উদ্দেশ্যে এবং উভয়ই RLS-কে রক্ষার একমাত্র লাইন হিসাবে রেখে দেয়।
পরবর্তী পদক্ষেপ
আপনার production URL-এর বিরুদ্ধে একটি ফ্রি FixVibe scan চালান — baas.supabase-rls check ফ্রি tier সহ প্রতিটি plan-এ enabled। একটি Supabase project থেকে আর কী leak হতে পারে তার গভীর পাঠের জন্য, JavaScript-এ Supabase service role key উন্মোচিত এবং Supabase storage bucket security checklist দেখুন। সমস্ত BaaS providers-এর umbrella দৃশ্যের জন্য, BaaS misconfiguration scanner পড়ুন।
