RLS son savunma hattı değil. Tek savunma hattı.
Sperare'de danışmanın başkasının pasaportunu görememesi bir kontrol değil, veritabanının kendi kuralı. İstemciden gelen her sorguya güvenmek zorunda olduğunuzda tek yol bu.
Sperare'de kullanıcılar pasaport yüklüyor, diploma yüklüyor, banka dökümü yüklüyor. Bir göçmenlik dosyasında bulunan belgelerin listesi, birinin hayatının en hassas evrak yığını.
Böyle bir üründe sorulacak ilk soru şu: bir danışman, kendi müşterisi olmayan birinin belgesini görebilir mi? Ve bu sorunun cevabı "hayır, çünkü arayüzde o ekran yok" ise, ürün güvenli değil — sadece kurcalanmamış.
Neden uygulama katmanı yetmiyor
Klasik yaklaşımda yetki kontrolü sunucudaki servis katmanında yaşıyor. getDocuments(userId) çağrısı, isteyen kişinin o dosyaya erişimi olup olmadığını kontrol ediyor, sonra sorguyu atıyor.
Bu doğru bir katman ama tek katman olduğunda kırılgan. Çünkü kontrolü unutabileceğin her yeni endpoint, her yeni sorgu, her acele yazılmış rapor ekranı yeni bir sızıntı adayı. Ve bu tür hatalar test edilmiyor; kimse "yanlışlıkla fazla veri döndürüyor muyum" diye test yazmıyor. Herkes doğru cevabın döndüğünü test ediyor.
Supabase gibi istemcinin veritabanıyla doğrudan konuştuğu bir mimaride ise durum daha net: uygulama katmanı diye güvenebileceğin bir yer zaten yok. İstemci sorguyu kendi yazıyor.
Yetkiyi kodda tutarsan, kod her değiştiğinde yetki de değişme riski taşır. Yetkiyi veritabanında tutarsan, değiştirmek için niyet gerekir.
Kural satırın kendisinde yaşıyor
Row Level Security'nin fikri basit: erişim kuralı tablonun üstünde tanımlı ve her sorguya otomatik uygulanıyor. Kim sorarsa sorsun, nereden sorarsa sorsun.
Pratikte bunun anlamı şu oldu — bir belge satırı yalnızca sahibi olan kullanıcıya ve o dosyaya atanmış danışmana görünüyor. Bu kural bir fonksiyonda değil, tablonun politikasında yazılı. Yeni bir ekran yazdığımda o ekran için ayrıca yetki kontrolü eklemiyorum; ekleyemediğim şey zaten görünmüyor.
Bunun getirdiği rahatlık gerçek. Ama bedava değil.
RLS'in sana söylemedikleri
Politika yazmak sorgu yazmaktan zordur. Çünkü politikayı yazarken düşünmen gereken şey "bu sorgu ne döndürsün" değil, "bu tabloya gelebilecek her sorgu ne döndürmesin". Tersinden düşünmek alışkanlık gerektiriyor.
Performans sessizce kaçıyor. Politika her satır için değerlendiriliyor. İçinde alt sorgu olan bir politika, bin satırlık bir listede bin kez çalışabiliyor. Politikada kullandığın her alan indeksli olmak zorunda — bunu fark etmenin genelde tek yolu, üretimde birdenbire yavaşlayan bir sayfa.
Depolama ayrı bir dünya. Tablolarını mükemmel korurken dosya kovasını herkese açık bırakmak mümkün, ve bunu yapan çok ekip var. Belgeler kovada, kova politikası tabloların politikasından bağımsız. İkisini birlikte düşünmezsen, veritabanı sızdırmıyor ama dosya URL'i sızdırıyor.
Servis anahtarı bütün kuralları atlar. Sunucu tarafında kullandığın yükseltilmiş anahtar RLS'i tamamen devre dışı bırakıyor. Yani o anahtarın kullanıldığı her satır kod, aslında RLS'siz bir kod. Nerede kullandığını bilmek zorundasın.
Test edilmeyen politika, politika değil
En çok işime yarayan alışkanlık şu oldu: her politika için negatif test yazmak. Yalnızca "kendi belgesini görüyor mu" değil, "başkasının belgesini istediğinde boş dönüyor mu".
Bu testler sıkıcı, hızlı çalışıyor, ve bir gün birinin masum görünen bir politika değişikliğini yakalıyorlar. O gün geldiğinde, yazdığın on satır testin karşılığını fazlasıyla almış oluyorsun.