Kiracı Ayrımı — A Bankasının Müşterisi B Bankasının Verisini Görmesin
Önce şunu oku: Dinamik Sorgu — Filtre Ekranı Bir Kapıya Dönüşmesin
30 saniyede özet
Birçok bankaya hizmet veren bir platformda bütün satırlar aynı tablolardadır. Elle yazılan kiracı koşulu bir gün unutulur; @TenantId Hibernate sorgularını korur ama native SQL'i değil. Row-level security ayrımı verinin kendisine koyar.
Bir apartmanın bütün mektupları tek bir odaya geliyor. Postacı her mektupta daire numarasına bakıp doğru kutuya koyuyor. Bir gün bakmayı unutursa, birinin mektubu başkasının eline geçer.
-
Bayt: Cüzdan platformumuz üç bankaya hizmet veriyor. Hepsi aynı veritabanında, her satırda tenant_id var.
-
Sen: Her sorguya where tenant_id = :tenant yazıyoruz. Bugüne kadar sorun olmadı.
-
Bayt: Yeni hareket arama ekranında o koşul yok! A Bankası'nın müşterisi B'nin havalelerini görüyor.
-
Bayt: Koşulu her seferinde hatırlamak yerine, kutulara kilit takmamız gerekiyor.
Tek tablo, birçok banka
çok kiracılılıkTek bir uygulamanın birden çok müşteri kurumuna (kiracıya) hizmet vermesi. Her kiracı yalnızca kendi verisini görmelidir.Sözlükte gör → bir platformda bütün bankaların verisi çoğu zaman aynı tablolardadır. Hangi satırın kime ait olduğunu bir tenant_id sütunu söyler.
Ayrımı sağlayan şey her sorgudaki o koşuldur. Yüz sorgunun doksan dokuzunda yazılı olması yetmez; birinde unutulursa başka bankanın verisi görünür.
Kafam karıştı, daha basit anlat
Bütün bankalar aynı tabloda. Onları ayıran tek şey bir koşul; unutulursa veri sızar.
Birçok bankaya hizmet veren bir platformda tek veritabanı var ve her satırda tenant_id duruyor. En büyük risk nedir?
Her sorguya elle where tenant_id = :tenant yazmanın zayıf yanı nedir?
Koşulu kim ekler?
Hibernate'in @TenantId alanı açık. Aylık rapor native SQL ile yazılmış ve kiracı koşulu yok. Rapor kimin satırlarını getirir? Cevabı göster
Bütün bankaların. @TenantId koşulu yalnızca Hibernate’in ürettiği sorgulara ekler. Native SQL doğrudan veritabanına gider ve bu korumadan geçmez.
Adım adım oku
- Bütün mektuplar tek bir odada.
- Postacı her mektupta daireye bakıyor.
- Bir gün bakmayı unuttu.
- Kilitli kutu: anahtar yalnızca seninkini açar.
Hibernate’te bir alana @TenantId koymak, koşulu hatırlama işini geliştiriciden alır. Kaydederken kiracı alana yazılır, HQL ve JPQL sorgularına koşul kendiliğinden eklenir.
row-level securityVeritabanının, sorgu ne olursa olsun yalnızca bir politikaya uyan satırları göstermesi. PostgreSQL'de CREATE POLICY ile tanımlanır.Sözlükte gör → ise bir adım daha ileri gider. Kural veritabanının içindedir: sorgu JPQL de olsa native SQL de olsa, yalnızca o kiracının satırları görünür.
Kafam karıştı, daha basit anlat
@TenantId Hibernate sorgularını korur. Row-level security her sorguyu korur.
Hibernate'in @TenantId alanı ne yapar?
@TenantId kullanılıyor. Koşulsuz bir native SQL rapor sorgusu ne getirir?
Kendin gör
A Bankası’nın müşterisi dört ekran açıyor
Tohum 200360Oturum: A Bankası · tek veritabanı, her satırda tenant_id
- Hesaplarım (JPQL) · koşul elle yazılmış
- Kartlarım (JPQL) · koşul elle yazılmış
- Hareket arama (JPQL) · koşul yazılmamış
- Aylık rapor (native SQL) · koşul yazılmamış
✕ başka bankanın verisini gösteren ekran: 0
Şu an ne oldu?
Her sorguya elle: where tenant_id = :tenant
Her ekran bir sorgu çalıştırıyor. Sonuçta yalnızca A Bankası’nın satırları olmalı.
Görevler0/3
Unutulan bir koşul başka bankanın verisini göstersinaçık
İpucu
Elle koşul.
Yalnızca native SQL sızdırsınaçık
İpucu
Hibernate @TenantId.
Hiçbir ekran sızdırmasınaçık
İpucu
Veritabanında.
Olay günlüğü (0)
Henüz olay yok. Oynat veya adımla.
- Varsayılanla oynat. Koşullar elle yazılmış: hareket arama ve aylık rapor B Bankası’nın satırlarını da getirdi.
- “Hibernate @TenantId” seç. Hareket arama korundu; yalnızca native SQL rapor sızdırdı.
- “Row-level security” seç. Dört ekranın dördü de yalnızca A Bankası’nın verisini gösterdi.
PostgreSQL row-level security ne sağlar?
Kiracı bilgisi istekte nereden alınmalı?
Tuzaklar
Tablonun sahibiyle bağlanmak. PostgreSQL’de row-level security politikaları tablonun sahibine varsayılan olarak uygulanmaz. Uygulamayı ayrı bir kullanıcıyla bağla ya da FORCE ROW LEVEL SECURITY kullan.
Kiracıyı bağlantıya bir kez vermek. Bağlantı havuzundaki bir bağlantı sonra başka bir bankanın isteğine gider. Kiracıyı her işlemin başında SET LOCAL ile ver; işlem bitince kendiliğinden silinir.
Kiracıyı kullanıcıdan almak. Kiracı bilgisi URL’den ya da istek gövdesinden değil, doğrulanmış oturumdan ya da token’dan gelir.
Kafam karıştı, daha basit anlat
Sahip olmayan kullanıcıyla bağlan, kiracıyı her işlemde ver, kiracıyı token’dan al.
RLS kullanılıyor ama uygulama tabloların sahibi olan kullanıcıyla bağlanıyor. Ne olur?
Derinleş · Cüzdan platformu: üç banka, tek veritabanı 5 dosya · ~87 satır · ilk okumada atlayabilirsin
Kendini sına
Elle yazılan kiracı koşulu bir gün bir sorguda unutulabilir.
Bağlantı havuzunda RLS için kiracı bilgisi bağlantıya nasıl verilir?
Aklında kalacak üç şey
- 1 Paylaşılan tablolarda kiracıları ayıran şey bir koşuldur. Yüz sorgudan birinde unutulması bir sızıntı için yeter.
- 2 Hibernate'in @TenantId alanı, Hibernate'in ürettiği sorgulara koşulu kendisi ekler. Native SQL ise bu korumadan geçmez.
- 3 Row-level security ayrımı veritabanına koyar: sorgu ne olursa olsun yalnızca o kiracının satırları görünür.