FixVibe

// docs / baas security / supabase storage

Supabase storage bucket security checklist: 22 आइटम

Supabase Storage एक S3-संगत bucket के चारों ओर एक पतला wrapper है साथ ही database के समान Row-Level Security model। इसका मतलब है कि वही RLS pitfalls जो tables को प्रभावित करते हैं वे file access को भी प्रभावित करते हैं — और कुछ storage-specific जो तब सामने आते हैं जब AI कोडिंग टूल uploads को wire करते हैं। यह checklist पाँच sections में 22 आइटम है: bucket कॉन्फ़िगरेशन, RLS policies, upload validation, signed URLs, और operational hygiene। हर एक 15 मिनट से कम में verifiable है।

नीचे प्रत्येक आइटम आवश्यक है। अंतर्निहित RLS mechanics के लिए, Supabase RLS scanner देखें। Storage से सटे key-exposure class के लिए, JavaScript में Supabase service role key उजागर देखें।

Bucket कॉन्फ़िगरेशन

सही defaults से शुरुआत करें। एक गलत-कॉन्फ़िगर bucket files leak करता है चाहे आपका RLS सही हो या नहीं।

  1. हर bucket को default रूप से private रखें। Supabase Dashboard → Storage → Buckets में, Public bucket toggle को off पर सेट करें जब तक आपके पास कोई स्पष्ट कारण न हो (marketing assets, बिना PII वाले public avatars)। Public buckets read operations के लिए RLS को bypass करते हैं — bucket नाम वाला कोई भी व्यक्ति list और download कर सकता है।
  2. हर bucket पर एक hard file size limit सेट करें। Dashboard → Bucket settings → File size limit। User uploads के लिए 50 MB एक समझदार default है; video / large-file use cases के लिए इसे जानबूझकर बढ़ाएँ। बिना limit के, एक एकल दुर्भावनापूर्ण upload आपके storage quota या आपकी monthly bandwidth को समाप्त कर सकता है।
  3. प्रति bucket allowed MIME types को प्रतिबंधित करें। Allowed MIME types list — स्पष्ट allowlist, blocklist नहीं। केवल-image वाले buckets के लिए image/jpeg, image/png, image/webp। User-content bucket में कभी text/html, application/javascript, या image/svg+xml की अनुमति न दें — signed URL के माध्यम से serve होने पर ये browser में execute होते हैं।
  4. एक shared bucket नहीं, बल्कि प्रति content type एक bucket का उपयोग करें। Per-bucket settings (size, MIME types, RLS policies) वह granularity है जो आपके पास है। एक user-avatars bucket, एक document-uploads bucket, और एक public-assets bucket एक mixed bucket की तुलना में lock down करना आसान हैं।
  5. यदि frontend uploads तो CORS कॉन्फ़िगरेशन verify करें। यदि users browser से सीधे एक signed URL पर upload करते हैं, तो bucket CORS में आपका production origin सूचीबद्ध होना चाहिए। * केवल public buckets के लिए स्वीकार्य है — कभी user PII वाले buckets के लिए नहीं।

storage.objects पर RLS policies

Supabase Storage storage.objects table में file metadata store करता है। उस table पर RLS नियंत्रित करता है कि कौन files पढ़, upload, update, या delete कर सकता है। RLS के बिना, bucket का public/private flag आपकी एकमात्र सुरक्षा है।

  1. Confirm करें कि storage.objects पर RLS enabled है। SELECT rowsecurity FROM pg_tables WHERE schemaname = 'storage' AND tablename = 'objects'; को true लौटाना चाहिए। Supabase इसे नए projects पर default रूप से enable करता है; verify करें कि यह disable नहीं किया गया है।
  2. Private buckets के लिए auth.uid() पर scoped एक SELECT policy लिखें। CREATE POLICY "users_read_own_files" ON storage.objects FOR SELECT USING (auth.uid()::text = (storage.foldername(name))[1]);। Convention [user-id]/[filename] के तहत files को store करना और path से owner निकालने के लिए storage.foldername() का उपयोग करना है।
  3. एक INSERT policy लिखें जो उसी path convention को लागू करे। CREATE POLICY "users_upload_own" ON storage.objects FOR INSERT WITH CHECK (auth.uid()::text = (storage.foldername(name))[1]);। WITH CHECK के बिना, एक authenticated user किसी अन्य user के folder में upload कर सकता है।
  4. यदि आपकी app file edits या deletes का समर्थन करती है तो UPDATE और DELETE policies जोड़ें। हर command को अपनी policy चाहिए। DELETE छोड़ने का मतलब authenticated users अपनी फ़ाइलों को नहीं हटा सकते; UPDATE छोड़ने का मतलब file overwrites चुपचाप fail होते हैं।
  5. दो browser sessions में cross-user access का परीक्षण करें। User A के रूप में sign in करें, एक file upload करें, path copy करें। दूसरे browser में User B के रूप में sign in करें, REST API के माध्यम से file fetch करने का प्रयास करें। Response 403 या 404 होना चाहिए, कभी 200 नहीं।
sql
-- Confirm RLS on storage.objects
SELECT rowsecurity
FROM   pg_tables
WHERE  schemaname = 'storage' AND tablename = 'objects';

-- SELECT policy: scope reads to the owning user's folder.
CREATE POLICY "users_read_own_files"
  ON storage.objects
  FOR SELECT
  USING (auth.uid()::text = (storage.foldername(name))[1]);

-- INSERT policy: enforce the [user-id]/[filename] path convention.
CREATE POLICY "users_upload_own"
  ON storage.objects
  FOR INSERT
  WITH CHECK (auth.uid()::text = (storage.foldername(name))[1]);

Upload validation

हर upload को server-side validate करें, भले ही bucket में MIME और size constraints हों। AI कोडिंग टूल default रूप से client-only validation generate करते हैं; वह कुछ भी सुरक्षित नहीं करता।

  1. MIME type को file के वास्तविक bytes से server-side फिर से check करें, Content-Type header से नहीं। file-type (Node) जैसी library या magic-byte sniffing का उपयोग करें। एक हमलावर ऐसी file पर Content-Type: image/jpeg claim कर सकता है जो वास्तव में एक polyglot HTML / JavaScript payload है।
  2. Uploaded images से EXIF metadata strip करें। EXIF में GPS coordinates, device serial numbers, और timestamps हो सकते हैं। Storage से पहले strip करने के लिए .withMetadata(false) के साथ sharp या exif-parser का उपयोग करें।
  3. ऐसे SVGs को अस्वीकार करें जिनमें script tags या onload handlers हैं। SVG XML है — और कई AI-generated apps SVG uploads को "बस एक image" के रूप में अनुमति देती हैं। Server-side DOMPurify का उपयोग करें या SVG uploads को पूरी तरह अस्वीकार करें।
  4. Deterministic, unguessable filenames का उपयोग करें। मूल filename को preserve न करें। UUID या file contents का hash उपयोग करें। मूल filenames leak ("passport_scan_2024_01_15.jpg") करते हैं और predictable names enumeration को सक्षम बनाते हैं।

Signed URLs

Signed URLs वह तरीका है जिससे clients private buckets तक पहुँचते हैं। Expiry, bucket scope, और क्या log होता है — ये मायने रखते हैं।

  1. Signed-URL expiry को default रूप से 1 घंटा या उससे कम रखें। Supabase JS SDK का createSignedUrl(path, expiresIn) seconds लेता है। 31536000 (एक वर्ष) जैसे मान कभी उपयोग न करें — URL एक स्थायी अर्ध-public link बन जाता है।
  2. Signed URLs को कभी अपने database में store न करें। हर request पर server-side fresh generate करें। एक 1-वर्ष expiry वाली store की गई signed URL जो database dump से leak होती है, दीर्घकालिक access देती है।
  3. केवल file uploads नहीं, बल्कि signed-URL generation को log करें। यदि आप बाद में compromise का संदेह करते हैं, तो आपको पता होना चाहिए कि किसने कब कौन-सी URL generate की। auth.uid() + bucket + object path + timestamp log करें।
  4. User-uploaded files serve करते समय downloadAs option का उपयोग करें। createSignedUrl(path, expiresIn, { download: '.jpg' }) एक Content-Disposition: attachment header को मजबूर करता है ताकि file render होने के बजाय download हो — HTML / SVG / HTML-in-PDF execution class को हराता है।

Operational hygiene

Storage कॉन्फ़िगरेशन समय के साथ drift करती है। ये चार operational आइटम surface को tight रखते हैं।

  1. Buckets का त्रैमासिक audit करें। Dashboard → Storage → Buckets। Confirm करें कि public/private state और MIME-type lists app की अपेक्षाओं से मेल खाते हैं। "अस्थायी रूप से" बनाए गए Buckets स्थायी हो जाते हैं यदि कोई उन्हें हटाता नहीं है।
  2. Anonymous list operations को monitor करें। Storage logs (Dashboard → Logs → Storage) LIST requests को record करते हैं। private bucket के विरुद्ध anonymous list requests का एक spike मतलब कोई बाहर से इसकी जाँच कर रहा है।
  3. Ephemeral uploads के लिए एक retention policy सेट करें। Temp buckets (image preview, draft uploads) को एक scheduled function के माध्यम से 24-72 घंटों के बाद auto-delete होना चाहिए। GDPR / CCPA data-minimisation obligations के तहत अनिश्चित retention एक देयता है।
  4. मासिक FixVibe scan चलाएँ। baas.supabase-storage-public check ऐसे buckets के लिए probe करता है जो anonymous GET + LIST का जवाब देते हैं। नए buckets जुड़ते हैं; पुराने visibility बदलते हैं — केवल निरंतर scanning drift को पकड़ती है।

अगले कदम

अपने production URL के विरुद्ध एक FixVibe scan चलाएँ — anonymous storage listings baas.supabase-storage-public के तहत दिखाई देती हैं। Table layer के लिए Supabase RLS scanner और key-exposure adjacency के लिए JavaScript में Supabase service role key उजागर के साथ इस checklist को pair करें। अन्य BaaS providers में storage misconfigurations के लिए, BaaS misconfiguration scanner देखें।

// अपनी baas सतह को scan करें

किसी और के पहले खुली table खोजें।

एक प्रोडक्शन URL डालें। FixVibe उन BaaS providers की गिनती करता है जिनसे आपकी app बात करती है, उनके public endpoints का fingerprint लेता है, और बताता है कि एक unauthenticated client क्या पढ़ या लिख सकता है। मुफ़्त, बिना इंस्टॉल, बिना कार्ड।

  • मुफ़्त tier — 3 scans / माह, साइनअप के लिए कार्ड नहीं चाहिए।
  • Passive BaaS fingerprinting — domain verification की ज़रूरत नहीं।
  • Supabase, Firebase, Clerk, Auth0, Appwrite और अन्य।
  • हर finding पर AI fix prompts — Cursor / Claude Code में paste करें।
मुफ़्त BaaS scan चलाएँ

साइनअप की आवश्यकता नहीं

Supabase storage bucket security checklist: 22 आइटम — Docs · FixVibe