İçeriğe atla

Araştırma notları

2026-09-02

Kiracı sınırı iki katmanda: uygulama tek başına yetmiyordu

Ovodock'ta çoklu kiracı izolasyonu başlangıçta yalnız uygulama katmanındaydı: Eloquent'in global scope'u her sorguya kiracı süzgecini otomatik ekliyordu. Bu tek katmanlı bir savunmaydı — kiracı-üstü çalışması gereken senkron ve sağlık kontrolü gibi işlerin yazdığı türden tek bir `withoutGlobalScope('tenant')` satırı, veritabanından komşu kiracının satırlarını da alabiliyordu.

Çözümü PostgreSQL'in satır düzeyi güvenliği (RLS) taşıdı, ama düz bir politika yetmezdi: RLS varsayılan olarak tablo sahibini muaf tutar ve uygulama tam olarak tabloların sahibiyle bağlanıyordu — yani politika yazmak, koruma sanılan bir hiçlik olurdu. `FORCE ROW LEVEL SECURITY` sahibi de politikaya tabi kıldı; okuma ve yazma aynı ölçüte bağlandı (`USING` + `WITH CHECK`), kiracı belirsizken karşılaştırma NULL döner ve hiçbir satır eşleşmez — varsayılan ret.

İlk uygulama on bir tabloyu kapsadı; dördü (kiracının kendisi, üyelikler, davetler, olay kuyruğu) kiracı belirlenmeden okunmak zorunda olduğu için gerekçeyle dışarıda bırakıldı. Ama yetkinin taşındığı ara tablo bu listenin hiçbirine girmemişti — muaf değil, unutulmuştu. Politika devredeyken kısıtlı bir rolle çalışan bir yazmanın komşu kiracının üyesine rol atayabildiği ölçüldü; o tablo ardından politika altına alındı.

Elle tutulan bir tablo listesi, korumak için kurulduğu unutkanlığın kendisini taşır. Bunun yerine kapsamı sayan bir test yazıldı: veritabanının kendi kataloğunu okuyor, kiracı sütunu taşıyan her tabloyu buluyor ve her birinin ya politika altında ya da gerekçeli bir beyanla dışarıda olduğunu doğruluyor. Bu kapının ilk koşuşu üç tabloyu daha unutulmuş olarak yakaladı.

Politikanın kendisi de tek başına yeterli değil: superuser ya da atlama yetkili bir rolle bağlanan bir uygulama, `FORCE` dahil bütün politikaları aşar. Bunu sessiz bırakmak yerine sağlık kontrolüne bir sinyal eklendi — bağlantı rolü veritabanı kataloğundan sorgulanıyor, aşabiliyorsa arıza olarak bildiriliyor. Bunların hepsi PostgreSQL'e özgü davranışlar olduğu için test takımı SQLite'tan PostgreSQL'e taşındı: SQLite'ta RLS'in ne migration'ı çalışır ne testi, yani politika hiçbir yerde doğrulanamazdı.

Bugün burada tek not var. İkinci not yayımlandığında bu sayfa bir listeye döner.