Supabase और Firebase के access नियम (CWE-862): Row Level Security न होने से डेटा कैसे उजागर होता है और इसे कैसे ठीक करें
Supabase और Firebase ऐप्स browser को एक सार्वजनिक key से सीधे database query करने देते हैं, इसलिए किसी विज़िटर और हर row के बीच केवल Row Level Security या Security Rules होते हैं। enable row level security के बिना SQL से बनी table, या allow read, write: if true पर छोड़ा गया Firestore नियम, कोई भी पढ़ और बदल सकता है। USING और WITH CHECK policies rows को लॉग-इन यूज़र तक कैसे सीमित करती हैं, PostgreSQL migration के उदाहरण के साथ।
आसान भाषा में (ELI5)
एक दफ़्तरी इमारत हर विज़िटर को एक ही लॉबी कार्ड देती है, जो ब्रोशर के पीछे छपा है। जब तक हर मंज़िल का दरवाज़ा खुलने से पहले आपकी पहचान जाँचता है, तब तक यह ठीक है। एक मंज़िल जल्दबाज़ी में तैयार हुई और उसके दरवाज़े पर कोई reader ही नहीं है, इसलिए लॉबी कार्ड से वह खुल जाता है और कोई भी अंदर जाकर फ़ाइलें पढ़ सकता है। Supabase की anon key वही लॉबी कार्ड है: इसे सार्वजनिक ही होना है। Row Level Security हर मंज़िल के दरवाज़े का reader है। उपाय है हर दरवाज़े पर reader लगाना और उसे सटीक बताना कि कौन किसकी फ़ाइलें देख सकता है।
इस पेज के मुख्य शब्द
- सार्वजनिक anon key
- Supabase की
anonkey और Firebase की web config ऐप bundle के अंदर जाती हैं, और कोई भी उन्हें कॉपी कर सकता है। ये project की पहचान करती हैं, यूज़र की नहीं, इसलिए ये गुप्त नहीं हैं और अकेले डेटा की रक्षा नहीं कर सकतीं। - Row Level Security (RLS)
- PostgreSQL की एक सुविधा जो हर query को policies से छानती है। Supabase का Table Editor नई tables पर इसे चालू करता है, पर SQL या migrations से बनी tables RLS बंद होने के साथ शुरू होती हैं, और डिफ़ॉल्ट अनुमतियाँ तब
anonऔरauthenticatedको हर row पढ़ने और बदलने देती हैं। - USING और WITH CHECK
USINGतय करता है कि यूज़र कौन-सी मौजूदा rows देख, बदल या मिटा सकता है;WITH CHECKतय करता है कि वह कौन-सी नई या बदली हुई rows लिख सकता है। insert या update पर केवलUSINGवाली policy यूज़र्स को दूसरे संगठन के लिए rows लिखने देती है।- service_role key
service_rolekey RLS को पूरी तरह बायपास करती है। इसकी जगह केवल सर्वर और edge functions में है, कभी browser या mobile ऐप में नहीं।- Firestore के test-mode नियम
- test mode में शुरू किए projects को ऐसे नियम मिलते हैं जो किसी तारीख़ तक सारी reads और writes की अनुमति देते हैं, और कई बाद में
allow read, write: if trueमें बदल दिए जाते हैं। नियमों कोrequest.auth.uidकी तुलना document के owner field से करनी चाहिए।
हमले का चरण-दर-चरण प्रवाह
हमलावर ऐप खोलता है
Supabase URL और anon key JavaScript bundle या mobile ऐप package में होती हैं।
वह सीधे table को query करता है
वह ऐप की स्क्रीनों को छोड़कर केवल anon key के साथ invoices के REST endpoint को बुलाता है। anon key और बिना यूज़र session के टेस्ट project को भेजी गई रिक्वेस्ट यह मामला दिखाती है।
database हर row लौटा देता है
RLS बंद है और anon के पास select अधिकार है, इसलिए PostgreSQL कोई फ़िल्टर नहीं लगाता और सभी संगठनों के invoices लौटा देता है।
डेटा लीक होता या बदलता है
अगर update और delete भी दिए हों, तो हमलावर records बदल या मिटा सकता है। 2025 में CVE-2025-48757 जारी हुआ, जब शोधकर्ताओं ने पाया कि एक AI app builder से बने 170 से ज़्यादा ऐप्स में RLS न होने से डेटा उजागर था।
सोर्स कोड: कमज़ोर बनाम सुरक्षित कार्यान्वयन
-- migration.sql: इस table पर RLS कभी चालू नहीं होता
create table public.invoices (
id bigint generated always as identity primary key,
org_id uuid not null references public.orgs (id),
customer text not null,
amount_cents bigint not null
);
-- सार्वजनिक anon key हर row पढ़, बदल और मिटा सकती है
grant select, insert, update, delete on public.invoices to anon, authenticated;
-- migration.sql: RLS चालू, anon से अधिकार वापस, हर command की एक policy
create table public.invoices (
id bigint generated always as identity primary key,
org_id uuid not null references public.orgs (id),
customer text not null,
amount_cents bigint not null
);
-- RLS चालू होने पर बिना policy के कोई access नहीं
alter table public.invoices enable row level security;
revoke all on public.invoices from anon;
-- यूज़र केवल अपने संगठनों के invoices देखते हैं
create policy "members read their org's invoices"
on public.invoices for select to authenticated
using (org_id in (select org_id from public.memberships where user_id = (select auth.uid())));
-- नई rows यूज़र के किसी संगठन की होनी चाहिए; update या delete policy नहीं
create policy "members add invoices to their org"
on public.invoices for insert to authenticated
with check (org_id in (select org_id from public.memberships where user_id = (select auth.uid())));
इंजीनियरिंग और सिस्टम सुरक्षा चेकलिस्ट
- खुले schemas की हर table पर RLS चालू करें, और जब
select tablename from pg_tables where schemaname = 'public' and not rowsecurityकोई row लौटाए तो CI फ़ेल करें। - हर command के लिए एक policy लिखें,
to authenticatedतक सीमित, reads के लिएUSINGऔर inserts व updates के लिएWITH CHECKके साथ; ग़ैर-ज़रूरी update और delete policies न बनाएँ। - जब anonymous यूज़र्स के पढ़ने की कोई वजह न हो तो
anonसे table की अनुमतियाँ वापस लें, औरservice_rolekey केवल सर्वर वातावरण में रखें। - आपकी policies जिन tables को पढ़ती हैं, जैसे
memberships, उन पर भी RLS चालू करें, ताकि यूज़र ख़ुद को दूसरे संगठन में न जोड़ सकें। - दो टेस्ट यूज़र्स से जाँचें: यूज़र A को यूज़र B के संगठन की शून्य rows मिलनी चाहिए; Firestore के लिए
@firebase/rules-unit-testingसे emulator पर नियमों के unit tests चलाएँ।