FixVibe

// docs / baas security / supabase rls scanner

Scanner RLS Supabase: temukan tabel dengan row-level security yang hilang atau rusak

Row-level security (RLS) adalah satu-satunya hal yang berdiri antara data pelanggan Anda dan internet ketika Anda merilis aplikasi berbasis Supabase. AI coding tools menghasilkan kode berbentuk RLS yang ter-compile, terkirim, dan diam-diam membocorkan data โ€” tabel dibuat tanpa RLS diaktifkan, policy yang membaca tetapi tidak pernah membatasi, predikat yang membandingkan kolom dengan dirinya sendiri. Artikel ini menunjukkan apa yang dapat dibuktikan scanner RLS Supabase dari luar, empat bentuk RLS rusak yang muncul di aplikasi vibe-coded, dan cara men-scan deployment Anda sendiri dalam kurang dari semenit.

Apa yang dapat dibuktikan scan RLS eksternal

Scan RLS pasif berjalan terhadap endpoint PostgREST yang dieksposisi Supabase di https://[project].supabase.co/rest/v1/. Ia hanya menggunakan key anon publishable โ€” key yang sama yang digunakan browser Anda โ€” dan menyondir metadata daftar tabel, baca anonim, dan tulis anonim. Ia tidak pernah berautentikasi sebagai user dan tidak pernah menyentuh privilege service-role. Apapun yang dapat ia lakukan, penyerang tidak terautentikasi di internet juga dapat melakukannya.

Dari luar database, scanner dapat mengonfirmasi hal berikut dengan kepercayaan tinggi:

  • RLS dinonaktifkan pada sebuah tabel. PostgREST mengembalikan baris untuk SELECT anonim ketika RLS mati atau ketika sebuah policy mengizinkannya. Kedua kasus adalah temuan.
  • Role anonim dapat membuat daftar tabel. GET /rest/v1/ dengan anon key mengembalikan skema OpenAPI untuk setiap tabel yang role anon miliki privilege apa pun di dalamnya. Aplikasi yang dihasilkan AI sering memberikan USAGE pada skema dan SELECT pada setiap tabel, yang mengekspos seluruh peta skema bahkan ketika RLS menolak baca yang sebenarnya.
  • Role anonim dapat melakukan insert. POST penyondiran dengan tebakan bentuk kolom akan berhasil jika RLS tidak memiliki policy INSERT yang menolaknya โ€” bahkan jika SELECT terkunci.
  • Service-role key ada di bundle browser. Berdekatan dengan RLS: jika scanner menemukan SUPABASE_SERVICE_ROLE_KEY atau JWT apa pun dengan role: service_role di bundle JavaScript, RLS tidak relevan โ€” pemegang key itu mem-bypass setiap policy.

Apa yang tidak dapat dibuktikan scan eksternal

Jujurlah tentang batasan scanner. Scan RLS eksternal tidak dapat membaca tabel pg_policies Anda, file migrasi Anda, atau predikat persis dari policy apa pun. Ia menyimpulkan dari perilaku black-box, yang berarti kadang-kadang ia akan melaporkan temuan yang ternyata data publik yang disengaja (tabel newsletter pemasaran, katalog produk publik). Laporan FixVibe menandai ini sebagai kepercayaan menengah ketika scanner tidak dapat membedakan niat โ€” periksa nama tabel dan putuskan.

Empat bentuk RLS rusak yang dihasilkan AI tools

Ketika Anda mengarahkan Cursor, Claude Code, Lovable, atau Bolt ke Supabase, empat pola RLS rusak yang sama muncul di ribuan aplikasi. Masing-masing lolos type-check, ter-compile, dan terkirim:

Bentuk 1: RLS tidak pernah diaktifkan

Mode kegagalan paling umum. Migrasi membuat tabel tetapi pengembang (atau AI tool) lupa ALTER TABLE ... ENABLE ROW LEVEL SECURITY. PostgREST dengan senang hati melayani seluruh tabel kepada siapa saja yang memiliki anon key. Fix: ALTER TABLE public.[name] ENABLE ROW LEVEL SECURITY; ALTER TABLE public.[name] FORCE ROW LEVEL SECURITY;. FORCE tidak opsional โ€” tanpanya, pemilik tabel (dan role apa pun dengan kepemilikan tabel) mem-bypass RLS.

sql
ALTER TABLE public.[name] ENABLE ROW LEVEL SECURITY;
ALTER TABLE public.[name] FORCE  ROW LEVEL SECURITY;

Bentuk 2: RLS diaktifkan, tanpa policy

Kegagalan yang lebih halus. RLS diaktifkan tetapi tidak ada policy yang ditulis. Default di PostgreSQL adalah deny, jadi user terautentikasi tidak melihat apa-apa โ€” dan pengembang menambahkan USING (true) agar aplikasi bekerja, yang mengizinkan semua orang membaca semuanya. Fix: tulis policy yang dibatasi oleh auth.uid(): CREATE POLICY "select_own" ON public.[name] FOR SELECT USING (auth.uid() = user_id); dan policy INSERT/UPDATE/DELETE yang sepadan.

sql
CREATE POLICY "select_own"
  ON public.[name]
  FOR SELECT
  USING (auth.uid() = user_id);

Bentuk 3: Policy membandingkan kolom dengan dirinya sendiri

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.

Bentuk 4: Policy pada SELECT tetapi tidak pada INSERT/UPDATE

Pengembang mengunci baca tetapi lupa tulis. Policy RLS bersifat per-command. FOR SELECT hanya melindungi baca; klien anonim masih dapat INSERT jika tidak ada policy yang menolaknya. Fix: buat policy per command, atau gunakan FOR ALL dengan klausa USING dan WITH CHECK eksplisit.

Cara kerja scanner RLS Supabase FixVibe

Check baas.supabase-rls berjalan dalam tiga tahap, masing-masing dengan tingkat kepercayaan eksplisit:

  1. Tahap 1 โ€” fingerprint. Scanner meng-crawl aplikasi yang ter-deploy, mem-parse bundle JavaScript-nya, dan mengekstrak URL proyek Supabase serta anon key dari konfigurasi runtime. Tanpa tebakan DNS, tanpa brute force โ€” ia membaca apa yang dibaca browser.
  2. Tahap 2 โ€” penemuan skema. Satu GET /rest/v1/ dengan anon key mengembalikan skema OpenAPI untuk setiap tabel yang dapat dilihat role anon. Scanner mencatat nama tabel tetapi tidak membaca data baris pada tahap ini.
  3. Tahap 3 โ€” sondir baca dan tulis. Untuk setiap tabel yang ditemukan, scanner mengeluarkan satu SELECT anonim dengan limit=1. Jika baris dikembalikan, RLS bersifat permisif. Scanner berhenti di situ โ€” ia tidak mengenumerasi baris, tidak melakukan paginasi, tidak memodifikasi data. Sondir INSERT diperketat di balik verifikasi kepemilikan domain dan opt-in eksplisit; sondir tersebut tidak pernah berjalan terhadap target yang belum diverifikasi.

Setiap temuan disertai URL request persis, status response, bentuk response (header-only), dan nama tabel. Prompt perbaikan AI di bawah temuan adalah blok SQL salin-tempel yang Anda jalankan di editor SQL Supabase.

Apa yang harus dilakukan ketika scanner menemukan sesuatu

Setiap temuan RLS adalah keadaan darurat runtime. Endpoint PostgREST publik di-scan oleh penyerang dalam hitungan menit. Urutan remediasi bersifat mekanis:

  1. Audit setiap tabel. Jalankan SELECT schemaname, tablename, rowsecurity FROM pg_tables WHERE schemaname = 'public'; di editor SQL Supabase. Setiap baris dengan rowsecurity = false adalah masalah.
  2. Aktifkan RLS pada setiap tabel publik. Default ke ENABLE ROW LEVEL SECURITY dan FORCE ROW LEVEL SECURITY pada setiap tabel yang dibuat โ€” jadikan ini template migrasi.
  3. Tulis policy command-per-command. Jangan gunakan FOR ALL USING (true). Tulis policy eksplisit untuk SELECT, INSERT, UPDATE, DELETE โ€” masing-masing dibatasi pada auth.uid() atau kolom org-id dari auth.jwt().
  4. Verifikasi dengan akun kedua. Daftar sebagai user yang berbeda, coba baca catatan user lain melalui REST API secara langsung. Jika response adalah 200, policy rusak.
  5. Scan ulang. Setelah menerapkan fix, jalankan kembali scan FixVibe terhadap URL yang sama. Temuan baas.supabase-rls seharusnya hilang.
sql
-- 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;

Bagaimana ini dibandingkan dengan scanner lain

Sebagian besar tool DAST generik (Burp Suite, OWASP ZAP, Nessus) tidak tahu apa itu PostgREST. Mereka akan meng-crawl aplikasi Anda, mengabaikan path /rest/v1/, dan melaporkan halaman HTML yang mereka pahami. Snyk dan Semgrep adalah tool analisis statis โ€” mereka menemukan file migrasi di repo Anda dengan panggilan RLS yang hilang, tetapi tidak dapat membuktikan database yang ter-deploy salah konfigurasi. FixVibe duduk di celah itu: pasif, sadar-BaaS, fokus pada apa yang dapat dibuktikan penyerang tidak terautentikasi dari URL publik.

Pertanyaan yang sering diajukan

Apakah scanner membaca atau memodifikasi data saya?

Tidak. Scan pasif mengeluarkan paling banyak satu SELECT ... limit=1 per tabel yang ditemukan untuk mengonfirmasi apakah RLS mengizinkan baca anonim. Scanner mencatat bentuk response, bukan isi baris. Sondir INSERT, UPDATE, dan DELETE diperketat di balik verifikasi kepemilikan domain dan tidak pernah berjalan terhadap target yang belum diverifikasi.

Apakah ini bekerja jika proyek Supabase saya dijeda atau berada di domain kustom?

Proyek yang dijeda mengembalikan 503 pada setiap request โ€” scanner melaporkan proyek sebagai tidak terjangkau. Domain kustom bekerja selama aplikasi yang ter-deploy masih memuat SDK klien Supabase di browser; scanner mengekstrak URL proyek dari bundle bagaimanapun juga.

Bagaimana jika anon key saya dirotasi atau publishable key saya berubah?

Jalankan kembali scan. Scanner mengekstrak ulang key dari bundle saat ini pada setiap run. Rotasi hanya menginvalidasi laporan sebelumnya, bukan keadaan policy database.

Apakah scanner memeriksa model publishable-key Supabase yang baru (<code>sb_publishable_*</code>)?

Ya. Detektor mengenali JWT anon lama dan key sb_publishable_* yang lebih baru, serta memperlakukannya secara identik โ€” keduanya dimaksudkan untuk publik dan keduanya menyisakan RLS sebagai satu-satunya garis pertahanan.

Langkah berikutnya

Jalankan scan FixVibe gratis terhadap URL produksi Anda โ€” check baas.supabase-rls diaktifkan di setiap paket termasuk tier gratis. Untuk bacaan lebih dalam tentang apa lagi yang dapat bocor dari proyek Supabase, lihat Supabase service role key terekspos di JavaScript dan Checklist keamanan bucket storage Supabase. Untuk tinjauan menyeluruh lintas semua penyedia BaaS, baca 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

Scanner RLS Supabase: temukan tabel dengan row-level security yang hilang atau rusak โ€” Docs ยท FixVibe