---
title: "Kurumsal Yazılımda Çok Kiracılı (Multi-Tenant) Veri Yalıtımı"
url: "https://cilginyazilim.com/blog/cok-kiracili-multi-tenant-veri-yalitimi"
description: "Çok kiracılı sistemlerde veri sızıntısı nasıl önlenir? Ayrı veritabanı, ayrı şema ve paylaşımlı tablo karşılaştırması; otomatik kiracı filtresi örneğiyle."
published: "2026-09-23T10:00:00+03:00"
modified: "2026-09-23T10:00:02+03:00"
author: "Çılgın Yazılım"
category: "Kurumsal Yazılım ve Entegrasyon"
tags: ["php", "codeigniter", "mimari", "veritabanı", "güvenlik", "ölçeklenme", "idor", "kurumsal yazılım", "çok kiracılı", "yetkilendirme", "multi-tenant", "veri yalıtımı", "saas"]
site: "Çılgın Yazılım"
language: "tr"
---

# Kurumsal Yazılımda Çok Kiracılı (Multi-Tenant) Veri Yalıtımı

Tek bir eksik WHERE koşulu, bir müşterinin verisini başka müşteriye gösterir. Yalıtımı umuda değil yapıya bağlayın.

**Çok kiracılı** bir sistemde tek bir uygulama birden fazla müşteriye (kiracıya) hizmet eder. Kurumsal yazılımda bu model işletme maliyetini belirgin biçimde düşürür; buna karşılık tek bir hata sınıfı ölümcül hâle gelir: bir müşterinin verisinin diğerine görünmesi.

![Çok kiracılı yalıtım modellerinin karşılaştırması](https://cilginyazilim.com/uploads/blog/2026/08/cok-kiracili-multi-tenant-veri-yalitimi-ozet.png)
*Paylaşımlı tabloda güvenlik, hatırlanan bir WHERE koşuluna bağlıysa zaten kaybedilmiştir.*

## Üç model, üç maliyet

**Ayrı veritabanı** en güçlü yalıtımı verir; yedekleme ve geri yükleme müşteri bazında yapılabilir, gürültülü komşu sorunu yoktur. Bedeli işletmedir: yüz müşteri, yüz göç çalıştırması demektir.

**Ayrı şema** orta yoldur, ancak şema sayısı arttıkça bağlantı yönetimi ve göç koordinasyonu zorlaşır.

**Paylaşımlı tablo** (her satırda `tenant_id` sütunu) en ucuz ve en yaygın modeldir — ve doğru kurulmazsa en risklidir.

## Asıl tehlike: unutulan WHERE

```php
// Bu kod çalışır, test geçer, kod incelemesinden geçer —
// ve ÜRETİMDE başka müşterinin siparişini gösterir.
public function detay(int $id)
{
    $siparis = $this->siparisModel->find($id);     // tenant_id koşulu YOK

    return view('siparis/detay', ['siparis' => $siparis]);
}
```

Bu hatanın özelliği, tek müşterili test verisiyle asla ortaya çıkmamasıdır. Sızıntı ancak üretimde, gerçek müşteriler arasında görünür. Bu yüzden çözüm "dikkatli olmak" olamaz.

## Çözüm: filtreyi altyapıya gömün

Doğru yaklaşım, ayrım koşulunu her sorguya elle eklemek değil, eklenmemesini *imkânsız* kılmaktır. CodeIgniter'da bunu temel bir model sınıfıyla yapabilirsiniz.

```php
abstract class TenantModeli extends \CodeIgniter\Model
{
    /** Model müşteriye bağlı mı? (ortak referans tablolarında false) */
    protected bool $tenantaBagli = true;

    protected function tenantId(): int
    {
        $id = (int) (session()->get('tenant_id') ?? 0);

        // Bağlam yoksa sorgu ÇALIŞMAMALI — açık kapı bırakmaktansa hata verin
        if ($id <= 0) {
            throw new \RuntimeException('Müşteri bağlamı yok; sorgu reddedildi.');
        }

        return $id;
    }

    /** Her okuma bu kapıdan geçer */
    protected function kapsam(): self
    {
        if ($this->tenantaBagli) {
            $this->where($this->table . '.tenant_id', $this->tenantId());
        }

        return $this;
    }

    public function bul(int $id): ?array
    {
        return $this->kapsam()->where($this->table . '.id', $id)->first();
    }

    public function hepsi(): array
    {
        return $this->kapsam()->findAll();
    }

    /** Yazarken bu kimlik İSTEMCİDEN alınmaz, oturumdan yazılır */
    protected function tenantEkle(array $veri): array
    {
        if ($this->tenantaBagli) {
            $veri['tenant_id'] = $this->tenantId();
        }

        return $veri;
    }
}
```

> `tenant_id` alanını asla istemciden gelen veriyle doldurmayın ve `allowedFields` listesine koymayın. Aksi hâlde form gövdesine elle bir kimlik ekleyen kullanıcı, kaydı başka müşteriye yazabilir — bu, toplu atama (mass assignment) açığının en tehlikeli biçimidir.

## Veritabanı tarafında ikinci kapı

Uygulama katmanı tek savunma olmamalıdır. İki ek önlem işe yarar: benzersizlik kısıtlarını ayrım sütunuyla birlikte tanımlamak ve yabancı anahtarların aynı müşteri içinde kalmasını zorlamak.

```sql
-- YANLIŞ: e-posta tüm sistemde benzersiz → farklı müşteriler çakışır
UNIQUE KEY uq_eposta (eposta)

-- DOĞRU: benzersizlik müşteri İÇİNDE geçerli
UNIQUE KEY uq_kiraci_eposta (tenant_id, eposta)

-- Bileşik yabancı anahtar: kalem, siparişin sahibiyle aynı olmak ZORUNDA
ALTER TABLE siparis_kalemleri
  ADD CONSTRAINT fk_kalem_siparis
  FOREIGN KEY (tenant_id, siparis_id)
  REFERENCES siparisler (tenant_id, id);
```

Bileşik yabancı anahtar, uygulama katmanında bir hata olsa bile çapraz müşteri ilişkisi kurulmasını veritabanı seviyesinde engeller.

## Test edilebilir hâle getirin

Yalıtımı doğrulayan testler, tek müşterili verilerle yazılan testlerden farklıdır: iki ayrı hesap oluşturup birinin diğerinin kaydına erişemediğini *açıkça* sınamalısınız. Bu testi bir kez yazıp her yeni modül için tekrarlamak, sızıntıyı üretimden önce yakalar. Kayıt bazlı yetki kontrollerinin nasıl kurulacağını [yetkilendirme modelini doğru kurmak](https://cilginyazilim.com/blog/kurumsal-yazilimda-yetkilendirme-modelini-dogru-kurmak) yazımızda ele almıştık; [denetim izi](https://cilginyazilim.com/blog/kurumsal-yazilimda-denetim-izi-audit-log) ise sızıntı şüphesinde kimin neye eriştiğini geriye dönük görmenizi sağlar.

Müşteri bazlı özellik açma ihtiyacınız varsa bunu ayrım katmanına değil, [özellik bayrağı](https://cilginyazilim.com/blog/ozellik-bayraklari-feature-flag) sistemine taşımak daha sürdürülebilir olur.

## Model seçimini erteleyin mi?

Paylaşımlı tablodan ayrı veritabanına geçmek mümkündür ama pahalıdır. Bu yüzden karar, müşteri sayısı ve uyumluluk gereksinimine göre baştan verilmelidir: birkaç büyük kurumsal hesap ve sıkı veri ayrımı şartı varsa ayrı veritabanı, çok sayıda küçük müşteri varsa paylaşımlı tablo genelde doğru tercihtir. Büyük geçişlerin riskini büyük patlama göç stratejisi yazımızda tartışmıştık. Kısıt tanımlarının ayrıntısı için [MySQL yabancı anahtar belgeleri](https://dev.mysql.com/doc/refman/8.0/en/create-table-foreign-keys.html) başvurulabilir.

## Sonuç

Çok kiracılı bir sistemde veri yalıtımı, geliştiricinin her sorguda hatırlaması gereken bir kural olamaz — çünkü er ya da geç unutulur ve hata ancak üretimde görünür. Yalıtımı yapıya gömün: sorguları ayrım kapsamını zorunlu kılan bir temel modelden geçirin, bu kimliği istemci verisinden asla almayın, benzersizlik kısıtlarını ayrım sütunuyla birlikte tanımlayın ve bileşik yabancı anahtarlarla veritabanı seviyesinde ikinci kapıyı kurun. Bir sonraki modülünüzü yazarken şu soruyu sorun: "Bu sorguda ayrım koşulunu yazmayı unutsam, sistem beni durdurur mu?" Cevap hayırsa, düzeltilecek şey sorgu değil altyapıdır.

## Sıkça Sorulan Sorular

### Paylaşımlı tabloda performans sorun olur mu?

tenant_id sütunu bileşik indekslerin ilk alanı olduğu sürece genelde olmaz. Sorun büyük kiracıların küçükleri etkilemesidir (gürültülü komşu). Bu noktaya gelindiğinde en büyük kiracıları ayrı veritabanına taşımak, tüm modeli değiştirmekten daha pratiktir.

### Kiracı kimliğini alt alan adından (subdomain) almak güvenli mi?

Alt alan adı kiracıyı belirlemek için uygundur, ancak tek başına yetki kanıtı değildir. Oturumdaki kullanıcının o kiracıya gerçekten bağlı olduğunu her istekte doğrulamanız gerekir; aksi hâlde adres çubuğunu değiştiren biri başka kiracının bağlamına geçmeyi deneyebilir.

### Yönetici kullanıcılar tüm kiracıları görebilmeli, bunu nasıl yaparım?

Kapsamı bypass eden ayrı ve açıkça adlandırılmış bir yol tanımlayın; varsayılan davranışı gevşetmeyin. Ayrıca bu erişimlerin tamamını denetim iziyle kaydedin — çapraz kiracı erişimi her zaman kayda değer bir olaydır.

### Raporlama sorgularında kapsam nasıl korunur?

Raporlar genelde ham SQL ile yazıldığı için otomatik kapsamın dışında kalır ve en sık sızıntı burada olur. Rapor sorgularını da tek bir yardımcı katmandan geçirin ve kiracı parametresini zorunlu argüman yapın; isteğe bağlı bir parametre er ya da geç boş geçilir.

---

Kaynak: [Kurumsal Yazılımda Çok Kiracılı (Multi-Tenant) Veri Yalıtımı](https://cilginyazilim.com/blog/cok-kiracili-multi-tenant-veri-yalitimi)
