Supabase Row Level Security (RLS): tablolarını kilitle
Supabase, Postgres tablolarını Data API'si üzerinden doğrudan tarayıcıya açar ve bu API herkese açık anon (publishable) key ile kimlik doğrular. Hangi kullanıcının hangi satırları okuyup değiştirebileceğine Row Level Security (RLS) policy'leri karar verir. public şemasında RLS'i olmayan bir tablo, siteni açan herkes tarafından okunabilir — çoğu zaman da yazılabilir.
Nedir
Her Supabase projesi, frontend'de yaşaması amaçlanan bir anon (veya sb_publishable_) key ile gelir. Bu key kullanıcını değil projeni tanımlar — herkes onu JavaScript bundle'ından kopyalayıp https://<project>.supabase.co/rest/v1/ adresine kendisi istek gönderebilir ve arayüzünü tamamen atlayabilir.
Row Level Security, bir tabloya policy'ler ekleyen bir Postgres özelliğidir: her SELECT, INSERT, UPDATE ve DELETE işleminde her satır için kontrol edilen SQL koşulları. RLS etkin ve hiç policy yoksa, API üzerinden hiçbir şeye erişilemez. Eklediğin her policy tam olarak bir kapı açar — örneğin "oturum açmış kullanıcılar, user_id'si kendi id'leriyle eşleşen satırları okuyabilir".
Neden önemli
Eksik veya fazla geniş bir policy küçük bir bug değil, tam bir veri ihlalidir: kullanıcı e-postaları, profiller, siparişler, özel mesajlar — tabloda ne varsa — tek bir curl komutuyla dökülebilir. AI kodlama araçları tabloları sıklıkla RLS'in varsayılan olarak kapalı olduğu SQL migration'ları ile oluşturur ve uygulama çalışsın diye using (true) gibi gevşek yer tutucu policy'ler üretir.
service_role (sb_secret_) key'i RLS'i tamamen atlar. İstemci tarafı koda düşerse, yazdığın her policy anlamsız hale gelir — onu elinde tutan herkes veritabanına tam okuma/yazma erişimine sahip olur.
Nasıl düzeltilir
Açığa çıkan public şemasında RLS'i hâlâ kapalı olan her tabloyu listelemek için bunu Supabase SQL editor'da çalıştır. Dashboard'daki Security Advisor da aynı sorunu "RLS disabled in public" olarak raporlar.
select tablename
from pg_tables
where schemaname = 'public'
and rowsecurity = false;Her tablo için RLS'i aç, ardından her işlem için bir policy ekle. Policy'leri authenticated rolüyle sınırla ve satırın sahip sütununu auth.uid() ile karşılaştır. Insert ve update işlemleri with check gerektirir; böylece kullanıcılar başkasına ait satırlar yazamaz.
alter table public.profiles enable row level security;
create policy "Users read own profile"
on public.profiles for select
to authenticated
using ((select auth.uid()) = user_id);
create policy "Users update own profile"
on public.profiles for update
to authenticated
using ((select auth.uid()) = user_id)
with check ((select auth.uid()) = user_id);using (true) gibi yer tutucu policy'leri gerçek koşullarla değiştir. Yetkilendirmeyi user_metadata'ya dayandırma — kullanıcılar onu kendileri düzenleyebilir; bunun yerine app_metadata veya bir roller tablosu kullan. View'lar security_invoker = true ile oluşturulmadıkça RLS'i atlar ve storage bucket'ları storage.objects üzerinde kendi policy'lerine ihtiyaç duyar.
API'ni tam olarak bir saldırganın yapacağı gibi sorgula: yalnızca herkese açık key ile ve hiçbir kullanıcı oturumu olmadan. Bu istek herkese açık olmaması gereken satırlar döndürüyorsa, policy'lerin fazla açıktır.
curl "https://<project>.supabase.co/rest/v1/profiles?select=*" \
-H "apikey: <anon-key>" \
-H "Authorization: Bearer <anon-key>"service_role (sb_secret_) key'ini yalnızca API route'ları veya Edge Functions gibi sunucu kodunda kullan, asla NEXT_PUBLIC_ veya VITE_ öneki arkasında değil. Bir kez bile tarayıcıya gönderildiyse, dashboard'dan rotate et.
SSS
Supabase anon key'imin tarayıcıda görünmesi güvenli mi?
Evet — anon (publishable) key herkese açık olacak şekilde tasarlanmıştır, ancak yalnızca açığa çıkan her tabloda doğru policy'lerle RLS etkinse. Key'in kendisi, policy'lerinin izin vermediği hiçbir şeyi sağlamaz.
RLS'i etkinleştirdim ve uygulamam artık boş sonuç döndürüyor. Bozuk mu?
Bu, RLS'in amaçlandığı gibi çalıştığını gösterir: hiç policy yoksa her satır reddedilir. RLS'i yeniden kapatmak yerine, uygulamanın ihtiyaç duyduğu işlemler için doğru kullanıcılarla sınırlı policy'ler ekle.
AppSafe RLS policy'lerimi test ediyor mu?
AppSafe veritabanına giriş yapmaz, bu yüzden policy'lerini değerlendiremez — yukarıdaki SQL ve curl kontrollerini kullan. Ancak JavaScript'ini Supabase key'leri için tarar. Bir key raporlanırsa, JWT'nin orta kısmını decode et ve role claim'ini kontrol et: tarayıcıda anon beklenen bir durumdur, service_role ise kritik bir sızıntıdır.
Uygulaman etkileniyor mu?
AppSafe, bunu ve onlarca başka sorunu tek bir ücretsiz taramada kontrol eder.
Uygulamamı ücretsiz taraİlgili rehberler
Firebase Security Rules: veritabanını açık bırakmayı bırak
Firebase config'in tasarım gereği herkese açık. Verileri kimin göreceğine kuralların karar verir.
İstemci tarafı JavaScript'te açığa çıkan API key'leri
Bundle'ındaki her şey herkese açıktır. Öyle davran.
Açıkta kalan veritabanı yedekleri: /backup.sql erişilebilir olduğunda ne olur
Erişilebilir bir .sql dump'ı, tüm veritabanını eksiksiz teslim etmek demektir.