FixVibe

// docs / baas security / supabase storage

Checklist keamanan bucket storage Supabase: 22 item

Supabase Storage adalah pembungkus tipis di atas bucket yang kompatibel dengan S3 ditambah model Row-Level Security yang sama dengan database. Itu berarti perangkap RLS yang sama yang memengaruhi tabel memengaruhi akses file โ€” ditambah beberapa yang spesifik storage yang muncul ketika AI coding tools menyiapkan upload. Checklist ini adalah 22 item di lima bagian: konfigurasi bucket, policy RLS, validasi upload, signed URL, dan kebersihan operasional. Masing-masing dapat diverifikasi dalam kurang dari 15 menit.

Setiap item di bawah ini esensial. Untuk mekanisme RLS yang mendasari, lihat Scanner RLS Supabase. Untuk kelas eksposur key yang berdekatan dengan storage, lihat Supabase service role key terekspos di JavaScript.

Konfigurasi bucket

Mulai dengan default yang tepat. Bucket yang salah konfigurasi membocorkan file terlepas apakah RLS Anda benar atau tidak.

  1. Set setiap bucket default ke privat. Di Dashboard Supabase โ†’ Storage โ†’ Buckets, atur toggle Public bucket ke off kecuali Anda memiliki alasan eksplisit (aset pemasaran, avatar publik tanpa PII). Bucket publik mem-bypass RLS untuk operasi baca โ€” siapa saja dengan nama bucket dapat membuat daftar dan mengunduh.
  2. Tetapkan batas ukuran file yang keras pada setiap bucket. Dashboard โ†’ Bucket settings โ†’ File size limit. 50 MB adalah default yang masuk akal untuk upload user; naikkan secara sengaja untuk kasus penggunaan video / file besar. Tanpa batas, satu upload jahat dapat menguras kuota storage atau bandwidth bulanan Anda.
  3. Batasi tipe MIME yang diizinkan per bucket. Daftar tipe MIME yang diizinkan โ€” allowlist eksplisit, bukan blocklist. image/jpeg, image/png, image/webp untuk bucket khusus gambar. Jangan pernah izinkan text/html, application/javascript, atau image/svg+xml di bucket konten user โ€” mereka mengeksekusi di browser ketika disajikan via signed URL.
  4. Gunakan satu bucket per jenis konten, bukan satu bucket bersama. Pengaturan per-bucket (ukuran, tipe MIME, policy RLS) adalah granularitas yang Anda miliki. Bucket user-avatars, bucket document-uploads, dan bucket public-assets lebih mudah dikunci daripada satu bucket campuran.
  5. Verifikasi konfigurasi CORS jika upload dari frontend. Jika user mengupload langsung dari browser ke signed URL, CORS bucket harus mencantumkan origin produksi Anda. * dapat diterima hanya untuk bucket publik โ€” tidak pernah untuk bucket yang berisi PII user.

Policy RLS pada storage.objects

Supabase Storage menyimpan metadata file di tabel storage.objects. RLS pada tabel itu mengontrol siapa yang dapat membaca, mengupload, memperbarui, atau menghapus file. Tanpa RLS, flag publik/privat bucket adalah satu-satunya perlindungan Anda.

  1. Konfirmasi RLS diaktifkan pada storage.objects. SELECT rowsecurity FROM pg_tables WHERE schemaname = 'storage' AND tablename = 'objects'; harus mengembalikan true. Supabase mengaktifkannya secara default pada proyek baru; verifikasi bahwa ia tidak dinonaktifkan.
  2. Tulis policy SELECT yang dibatasi ke auth.uid() untuk bucket privat. CREATE POLICY "users_read_own_files" ON storage.objects FOR SELECT USING (auth.uid()::text = (storage.foldername(name))[1]);. Konvensinya adalah menyimpan file di bawah [user-id]/[filename] dan menggunakan storage.foldername() untuk mengekstrak pemilik dari path.
  3. Tulis policy INSERT yang menegakkan konvensi path yang sama. CREATE POLICY "users_upload_own" ON storage.objects FOR INSERT WITH CHECK (auth.uid()::text = (storage.foldername(name))[1]);. Tanpa WITH CHECK, user terautentikasi dapat mengupload ke folder user lain.
  4. Tambahkan policy UPDATE dan DELETE jika aplikasi Anda mendukung edit atau hapus file. Setiap command memerlukan policy-nya sendiri. Melewatkan DELETE berarti user terautentikasi tidak dapat menghapus file mereka sendiri; melewatkan UPDATE berarti penimpaan file gagal secara diam-diam.
  5. Uji akses lintas-user di dua sesi browser. Masuk sebagai User A, upload file, salin path-nya. Masuk sebagai User B di browser lain, coba ambil file via REST API. Response harus 403 atau 404, tidak pernah 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]);

Validasi upload

Validasi setiap upload di sisi server, bahkan ketika bucket memiliki batasan MIME dan ukuran. AI coding tools menghasilkan validasi hanya-klien secara default; itu tidak melindungi apa-apa.

  1. Periksa ulang tipe MIME di sisi server dari byte sebenarnya file, bukan header Content-Type. Gunakan pustaka seperti file-type (Node) atau magic-byte sniffing. Penyerang dapat mengklaim Content-Type: image/jpeg pada file yang sebenarnya adalah payload poliglot HTML / JavaScript.
  2. Lepas metadata EXIF dari gambar yang diupload. EXIF dapat berisi koordinat GPS, nomor seri perangkat, dan timestamp. Gunakan sharp dengan .withMetadata(false) atau exif-parser untuk melepasnya sebelum penyimpanan.
  3. Tolak SVG yang berisi tag script atau handler onload. SVG adalah XML โ€” dan banyak aplikasi yang dihasilkan AI mengizinkan upload SVG sebagai "hanya gambar." Gunakan DOMPurify di sisi server atau tolak upload SVG sepenuhnya.
  4. Gunakan nama file yang deterministik dan tidak dapat ditebak. Jangan pertahankan nama file asli. Gunakan UUID atau hash dari isi file. Nama file asli bocor ("passport_scan_2024_01_15.jpg") dan nama yang dapat diprediksi memungkinkan enumerasi.

Signed URL

Signed URL adalah cara klien mengakses bucket privat. Kadaluarsa, lingkup bucket, dan apa yang dicatat penting.

  1. Default expiry signed-URL ke 1 jam atau kurang. createSignedUrl(path, expiresIn) dari SDK JS Supabase mengambil detik. Jangan pernah gunakan nilai seperti 31536000 (satu tahun) โ€” URL menjadi tautan semi-publik permanen.
  2. Jangan pernah menyimpan signed URL di database Anda. Hasilkan yang baru di sisi server pada setiap request. Signed URL yang tersimpan dengan expiry 1 tahun yang bocor via dump database memberikan akses jangka panjang.
  3. Catat pembuatan signed-URL, bukan hanya upload file. Jika Anda mencurigai kompromi di kemudian hari, Anda perlu tahu siapa yang membuat URL mana kapan. Catat auth.uid() + bucket + path objek + timestamp.
  4. Gunakan opsi downloadAs saat menyajikan file yang diupload user. createSignedUrl(path, expiresIn, { download: '.jpg' }) memaksa header Content-Disposition: attachment sehingga file diunduh alih-alih dirender โ€” mengalahkan kelas eksekusi HTML / SVG / HTML-in-PDF.

Kebersihan operasional

Konfigurasi storage menyimpang seiring waktu. Empat item operasional ini menjaga permukaan tetap ketat.

  1. Audit bucket setiap kuartal. Dashboard โ†’ Storage โ†’ Buckets. Konfirmasi keadaan publik/privat dan daftar tipe MIME sesuai dengan harapan aplikasi. Bucket yang dibuat "sementara" menjadi permanen jika tidak ada yang menghapusnya.
  2. Pantau operasi list anonim. Log storage (Dashboard โ†’ Logs โ†’ Storage) mencatat request LIST. Lonjakan request list anonim terhadap bucket privat berarti seseorang menyondirnya dari luar.
  3. Set policy retensi untuk upload ephemeral. Bucket temp (preview gambar, upload draft) harus auto-hapus setelah 24-72 jam via fungsi terjadwal. Retensi tak terbatas adalah liabilitas di bawah kewajiban minimalisasi data GDPR / CCPA.
  4. Jalankan scan FixVibe bulanan. Check baas.supabase-storage-public menyondir bucket yang merespons GET + LIST anonim. Bucket baru ditambahkan; yang lama mengubah visibilitas โ€” hanya scanning kontinu yang menangkap pergeseran.

Langkah berikutnya

Jalankan scan FixVibe terhadap URL produksi Anda โ€” listing storage anonim muncul di bawah baas.supabase-storage-public. Pasangkan checklist ini dengan Scanner RLS Supabase untuk lapisan tabel dan Supabase service role key terekspos di JavaScript untuk kedekatan eksposur key. Untuk miskonfigurasi storage di penyedia BaaS lain, lihat Scanner miskonfigurasi BaaS.

// scan permukaan baas anda

Temukan tabel terbuka itu sebelum orang lain menemukannya.

Masukkan URL produksi. FixVibe mengenumerasi penyedia BaaS yang berkomunikasi dengan aplikasi Anda, mengidentifikasi endpoint publiknya, dan melaporkan apa yang dapat dibaca atau ditulis oleh klien yang tidak terautentikasi. Gratis, tanpa instalasi, tanpa kartu.

  • Tier gratis โ€” 3 scan / bulan, tanpa kartu untuk pendaftaran.
  • Fingerprinting BaaS pasif โ€” tidak perlu verifikasi domain.
  • Supabase, Firebase, Clerk, Auth0, Appwrite, dan lainnya.
  • Prompt perbaikan AI di setiap temuan โ€” tempel kembali ke Cursor / Claude Code.
Jalankan scan BaaS gratis โ†’

tidak perlu pendaftaran

Checklist keamanan bucket storage Supabase: 22 item โ€” Docs ยท FixVibe