Tüm rehberler
Kritik önem derecesiVeritabanı Güvenliği

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

RLS'i olmayan tabloları bul

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;
RLS'i etkinleştir ve yalnızca sahibine izin veren policy'ler yaz

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);
Yaygın policy hatalarından kaçın

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.

Anon key ile dışarıdan test et

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 key'ini sunucuda tut

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