---
title: 'Satır Düzeyi Güvenlik'
source: 'https://academia.sh/tr/kurslar/veritabani-yonetimi/satir-duzeyi-guvenlik'
course: 'İlişkisel Veritabanı Yönetimi'
language: tr
updated: '2026-08-17T18:08:56+00:00'
license: 'CC BY-SA 4.0'
---

# Satır Düzeyi Güvenlik

Aynı tabloda hesaba göre farklı satır kümesi göstermek: politika ifadesi, oturum değişkeni, politikanın sızdırdığı satırların sayılması, yazma tarafındaki denetim ve politikanın erişim yoluyla etkileşimi.

Önceki ders izinleri nesne düzeyinde kurdu: bir hesap ödünç tablosunu ya okuyabiliyordu ya
okuyamıyordu. Kütüphanenin gerçek gereksinimi bu ikilikle karşılanmaz. Sahil şubesinin
görevlisi ödünç kayıtlarını okuyabilmelidir, ama yalnız kendi şubesinin satırlarını.
Merkez şubesinin satırlarını görmesi bir gereksinim değil, bir sızıntıdır.

Bu, nesne düzeyi izinle ifade edilemeyen bir kısıttır. Çözüm, tabloya erişimi tümden
açmak ya da kapatmak yerine, tabloya bir **politika (policy)** iliştirmektir: satırın
görünür olması için sağlaması gereken koşul. Motor, o tabloya giden her sorguya bu koşulu
kendiliğinden ekler. Buna **satır düzeyi güvenlik (row-level security)** denir.

## Politika İfadesi ve Oturum Değişkeni

Politika bir yüklemdir — satırın sütunlarını ve oturuma ait bir bilgiyi kullanan bir
koşul. Oturuma ait bilgi, bağlantı açılırken belirlenen ve sorgu içinden okunabilen bir
değerdir: hangi hesap bağlandı, o hesap hangi şubeye ait. Buna **oturum değişkeni
(session variable)** denir.

Kütüphane örneğindeki politika şudur: `sube_id`, oturumun şube numarasına eşit olmalı.
Sorgu `WHERE` yan tümcesine hiçbir şey yazmasa bile motor bu koşulu ekler; sorgu kendi
koşulunu yazmışsa iki koşul birlikte uygulanır.

Aşağıdaki örnek politikayı bir görünüm üzerinden modelliyor. Gerçek satır düzeyi güvenlik
politikayı taban tabloya iliştirir ve görünüm gerektirmez; burada modellenen şey politika
ifadesinin satır kümesini nasıl daralttığıdır, bu daraltma her iki durumda da aynıdır.

```bash
rm -f kutuphane.db
sqlite3 -box -header kutuphane.db <<'SQL'
CREATE TABLE odunc(
  id INTEGER PRIMARY KEY, kitap_id INT NOT NULL, uye_id INT NOT NULL,
  sube_id INT NOT NULL, alis TEXT NOT NULL, iade TEXT);
CREATE TABLE oturum(anahtar TEXT PRIMARY KEY, deger TEXT NOT NULL);

INSERT INTO odunc(kitap_id,uye_id,sube_id,alis,iade) VALUES
 (11,101,1,'2024-03-01','2024-03-14'),(12,102,1,'2024-03-03',NULL),
 (13,103,1,'2024-03-05',NULL),(14,104,2,'2024-03-02','2024-03-16'),
 (15,105,2,'2024-03-06',NULL),(16,106,2,'2024-03-08',NULL),
 (17,107,2,'2024-03-09','2024-03-20'),(18,108,3,'2024-03-04','2024-03-18'),
 (19,109,3,'2024-03-11',NULL);
INSERT INTO oturum VALUES ('sube_id','2');

CREATE VIEW odunc_gorunur AS
  SELECT * FROM odunc
  WHERE sube_id = (SELECT CAST(deger AS INTEGER) FROM oturum WHERE anahtar='sube_id');

SELECT 'taban tablo' AS kaynak, COUNT(*) AS satir FROM odunc
UNION ALL
SELECT 'politika sonrasi (sube 2)', COUNT(*) FROM odunc_gorunur;

UPDATE oturum SET deger='1' WHERE anahtar='sube_id';
SELECT 'politika sonrasi (sube 1)' AS kaynak, COUNT(*) AS satir FROM odunc_gorunur;
SQL
rm -f kutuphane.db
```

```text
┌───────────────────────────┬───────┐
│          kaynak           │ satir │
├───────────────────────────┼───────┤
│ taban tablo               │ 9     │
│ politika sonrasi (sube 2) │ 4     │
└───────────────────────────┴───────┘
┌───────────────────────────┬───────┐
│          kaynak           │ satir │
├───────────────────────────┼───────┤
│ politika sonrasi (sube 1) │ 3     │
└───────────────────────────┴───────┘
```

Sorgu metni değişmedi; yalnız oturum değeri değişti ve sonuç kümesi 4 satırdan 3 satıra
düştü. Politikanın anlamı budur: aynı sorgu, kim çalıştırdığına göre farklı satır kümesi
döndürür. Uygulama kodunda `WHERE sube_id = ?` yazmayı unutmak artık bir sızıntı
üretmez, çünkü koşulu uygulama değil motor koyar.

## Politikanın Sızdırdığı Satırların Sayılması

Politika bir kez yazılır ve yıllarca durur. Yazıldığı gün doğru olan bir koşul, sonradan
eklenen bir "kolaylık" ile genişleyebilir. Sık görülen genişleme şudur: iade edilmiş
kayıtların "artık gizli sayılmaması" gerektiği kararı verilir ve politikaya bir `OR`
eklenir.

Bu tür bir değişikliğin etkisi tahmin edilmez, **sayılır**. Amaçlanan satır kümesi ile
yürürlükteki politikanın döndürdüğü küme arasındaki fark, politikanın sızdırdığı
satırlardır.

```bash
rm -f politika.db
sqlite3 -box -header politika.db <<'SQL'
CREATE TABLE odunc(
  id INTEGER PRIMARY KEY, kitap_id INT NOT NULL, uye_id INT NOT NULL,
  sube_id INT NOT NULL, alis TEXT NOT NULL, iade TEXT);
INSERT INTO odunc(kitap_id,uye_id,sube_id,alis,iade) VALUES
 (11,101,1,'2024-03-01','2024-03-14'),(12,102,1,'2024-03-03',NULL),
 (13,103,1,'2024-03-05',NULL),(14,104,2,'2024-03-02','2024-03-16'),
 (15,105,2,'2024-03-06',NULL),(16,106,2,'2024-03-08',NULL),
 (17,107,2,'2024-03-09','2024-03-20'),(18,108,3,'2024-03-04','2024-03-18'),
 (19,109,3,'2024-03-11',NULL);

WITH
 amaclanan AS (SELECT id FROM odunc WHERE sube_id = 2),
 genis      AS (SELECT id FROM odunc WHERE sube_id = 2 OR iade IS NOT NULL)
SELECT
 (SELECT COUNT(*) FROM odunc)     AS taban,
 (SELECT COUNT(*) FROM amaclanan) AS amaclanan,
 (SELECT COUNT(*) FROM genis)     AS genis_politika,
 (SELECT COUNT(*) FROM genis WHERE id NOT IN (SELECT id FROM amaclanan)) AS sizan;

SELECT id, uye_id, sube_id, iade FROM odunc
WHERE (sube_id = 2 OR iade IS NOT NULL) AND sube_id <> 2 ORDER BY id;
SQL
rm -f politika.db
```

```text
┌───────┬───────────┬────────────────┬───────┐
│ taban │ amaclanan │ genis_politika │ sizan │
├───────┼───────────┼────────────────┼───────┤
│ 9     │ 4         │ 6              │ 2     │
└───────┴───────────┴────────────────┴───────┘
┌────┬────────┬─────────┬────────────┐
│ id │ uye_id │ sube_id │    iade    │
├────┼────────┼─────────┼────────────┤
│ 1  │ 101    │ 1       │ 2024-03-14 │
│ 8  │ 108    │ 3       │ 2024-03-18 │
└────┴────────┴─────────┴────────────┘
```

Sızan satır sayısı iki, ve hangileri olduğu listelendi: Merkez ve Tepe şubelerinin iade
edilmiş kayıtları, üye numaralarıyla birlikte Sahil görevlisine açılmış oldu. Dokuz
satırlık bir tabloda bu fark gözle görülür; on milyon satırlık bir tabloda yalnız bu
sorguyla görülür.

Bu sorgu bir denetim aracıdır ve politikanın her değişikliğinde çalıştırılır. Yazılışı
şablon hâline getirilebilir: amaçlanan koşulu bir ortak tablo ifadesine, yürürlükteki
politikayı bir başkasına koy, farkı say. Sıfırdan büyük her sonuç, politikanın metnine
bakmayı gerektirir.

## Yazma Tarafındaki Denetim

Politika okumayı daraltır. Yazmayı kendiliğinden daraltmaz. Bu ayrım, satır düzeyi
güvenliğin en sık atlanan yanıdır: Sahil görevlisi, Merkez şubesine ait bir ödünç kaydı
yazabilir ve yazdığı satırı sonradan göremez.

Aşağıdaki örnek bu durumu üretiyor. Görünüm üzerinden yapılan ekleme taban tabloya
gidiyor, ama eklenen satır politikanın dışında kaldığı için görünümde yok:

```bash
rm -f yazma.db
sqlite3 -box -header yazma.db <<'SQL'
CREATE TABLE odunc(id INTEGER PRIMARY KEY, kitap_id INT NOT NULL, uye_id INT NOT NULL,
                   sube_id INT NOT NULL, alis TEXT NOT NULL, iade TEXT);
CREATE TABLE oturum(anahtar TEXT PRIMARY KEY, deger TEXT NOT NULL);
INSERT INTO oturum VALUES ('sube_id','2');
INSERT INTO odunc(kitap_id,uye_id,sube_id,alis,iade) VALUES
 (15,105,2,'2024-03-06',NULL),(16,106,2,'2024-03-08',NULL);

CREATE VIEW odunc_gorunur AS
  SELECT * FROM odunc
  WHERE sube_id = (SELECT CAST(deger AS INTEGER) FROM oturum WHERE anahtar='sube_id');

CREATE TRIGGER odunc_gorunur_ekle INSTEAD OF INSERT ON odunc_gorunur
BEGIN
  INSERT INTO odunc(kitap_id,uye_id,sube_id,alis,iade)
  VALUES (NEW.kitap_id, NEW.uye_id, NEW.sube_id, NEW.alis, NEW.iade);
END;

INSERT INTO odunc_gorunur(kitap_id,uye_id,sube_id,alis,iade)
VALUES (20,110,3,'2024-03-12',NULL);

SELECT 'gorunumden' AS kaynak, COUNT(*) AS satir FROM odunc_gorunur
UNION ALL SELECT 'taban tablo', COUNT(*) FROM odunc;
SQL
rm -f yazma.db
```

```text
┌─────────────┬───────┐
│   kaynak    │ satir │
├─────────────┼───────┤
│ gorunumden  │ 2     │
│ taban tablo │ 3     │
└─────────────┴───────┘
```

Taban tabloda üç satır var, görünümde iki. Üçüncü satır yazıldı ve kayboldu. Bu, veri
bütünlüğü açısından okumadan sızıntı yapmaktan daha kötüdür: kimsenin göremediği ama var
olan kayıtlar birikir, sayımlar tutmaz ve neden bulunamaz.

Çözüm, aynı koşulun yazma yolunda da denetlenmesidir. Aşağıdaki tetikleyici, politikaya
uymayan satırı yazmadan reddediyor:

```bash
rm -f yazma2.db
sqlite3 yazma2.db <<'SQL'
CREATE TABLE odunc(id INTEGER PRIMARY KEY, kitap_id INT NOT NULL, uye_id INT NOT NULL,
                   sube_id INT NOT NULL, alis TEXT NOT NULL, iade TEXT);
CREATE TABLE oturum(anahtar TEXT PRIMARY KEY, deger TEXT NOT NULL);
INSERT INTO oturum VALUES ('sube_id','2');

CREATE VIEW odunc_gorunur AS
  SELECT * FROM odunc
  WHERE sube_id = (SELECT CAST(deger AS INTEGER) FROM oturum WHERE anahtar='sube_id');

CREATE TRIGGER odunc_gorunur_ekle INSTEAD OF INSERT ON odunc_gorunur
BEGIN
  SELECT CASE WHEN NEW.sube_id <>
      (SELECT CAST(deger AS INTEGER) FROM oturum WHERE anahtar='sube_id')
    THEN RAISE(ABORT, 'politika disi satir yazilamaz') END;
  INSERT INTO odunc(kitap_id,uye_id,sube_id,alis,iade)
  VALUES (NEW.kitap_id, NEW.uye_id, NEW.sube_id, NEW.alis, NEW.iade);
END;

INSERT INTO odunc_gorunur(kitap_id,uye_id,sube_id,alis,iade)
VALUES (20,110,3,'2024-03-12',NULL);
SQL
echo "cikis kodu: $?"
rm -f yazma2.db
```

```text
Runtime error near line 19: politika disi satir yazilamaz (19)
cikis kodu: 1
```

Tetikleyici sözdizimi ve hata iletisinin biçimi motora göre değişir; satır düzeyi
güvenliği yerleşik olarak destekleyen motorlarda aynı denetim politikanın ayrı bir
yanında tanımlanır. Değişmeyen kural şudur: her politikanın okuma tarafı ile yazma tarafı
ayrı ayrı yazılır ve ikisinin uyumu ayrıca sınanır.

## Politika ve Erişim Yolu

Politika yüklemi, sorgunun kendi koşuluna eklenen bir koşuldur; planlayıcı ikisini
birlikte görür. Bunun iki sonucu vardır.

Birincisi olumludur: politika sütunu üzerinde uygun bir dizin varsa, politika sorguyu
yavaşlatmaz — aksine seçiciliği artırdığı için hızlandırabilir. Önceki konuda kurulan
dizin ve bölümleme kararları burada işe yarar; şube numarasına göre bölümlenmiş bir tablo,
şube politikasıyla doğal biçimde uyuşur.

İkincisi dikkat gerektirir: politika yüklemi ile sorgunun kendi yüklemi arasındaki
değerlendirme sırası her zaman tanımlı değildir. Politika dışındaki bir satırın varlığı,
o satır üzerinde çalışan bir işlevin hata vermesi ya da yavaşlaması yoluyla dolaylı
olarak sezilebilir. Bu tür çıkarımlara karşı korunan motorlar politika yüklemini önce
değerlendirmeyi güvence altına alır. İşletim tarafındaki sorumluluk, politika taşıyan
tablolarda kullanıcı tanımlı işlevlerin yüklem olarak kullanılmasına izin vermemektir.

## Politikanın Kapsamadığı Yollar

Satır düzeyi güvenlik yalnız uygulandığı tablo üzerinden geçen erişimi denetler. Denetim
listesi şu soruları içerir.

**Tablo sahibi ve geniş yetkili hesaplar.** Motorlar genellikle tablo sahibini ve yönetici
hesabını politikadan muaf tutar. Uygulama hesabının tablo sahibi olmaması bu yüzden
önemlidir.

**Politikasız kopyalar.** Aynı verinin bir rapor tablosuna, bir maddeleştirilmiş görünüme
ya da bir dışa aktarım dosyasına kopyalanması, politikayı arkada bırakır. Kopyanın
kendisine de politika gerekir; gerekmiyorsa kopya politikanın kapsadığı alanı daraltacak
biçimde üretilir.

**Toplama işlevleriyle çıkarım.** Politika satırları gizler, sayıları gizlemeyebilir. Bir
hesabın göremediği satırlar üzerinde toplam ya da sayım alabildiği bir yol varsa, satır
içeriği olmasa da bilgi sızar. Toplama sorgularının politikadan sonra çalıştığını
doğrulamak, denetimin bir parçasıdır.

**Yedekler.** Bu ders boyunca kurulan her koruma, çalışan sisteme aittir. Yedek dosyası
politikasız bir kopyadır ve ayrı korunur — bu, sonraki dersin konusudur.

## Özet

- Satır düzeyi güvenlik, tabloya iliştirilen bir politika yüklemiyle aynı sorgunun kim
  çalıştırdığına göre farklı satır kümesi döndürmesini sağlar.
- Politika, oturum değişkenini kullanır; koşulu uygulama kodu değil motor ekler.
- Politika değişikliğinin etkisi tahmin edilmez, sayılır: amaçlanan küme ile yürürlükteki
  kümenin farkı sızan satırları verir.
- Okuma politikası yazmayı daraltmaz; yazma tarafı ayrıca denetlenmezse görünmeyen
  satırlar birikir.
- Politika yüklemi sorgu planına girer; politika sütununa uygun dizin ve bölümleme
  seçimi başarımı korur.
- Tablo sahibi, politikasız kopyalar, toplama üzerinden çıkarım ve yedek dosyaları
  politikanın kapsamadığı yollardır.

## Sonraki Adım

Erişim denetimi verinin yanlış kişiye gitmesini engeller; verinin yok olmasını
engellemez. Bir disk arızası, yanlış yazılmış bir `DELETE` ya da hatalı bir şema
değişikliği, en özenli yetki çizelgesine sahip veritabanını da kullanılamaz hâle getirir.
Sonraki ders yedeklemeye geçiyor: mantıksal, fiziksel ve artımlı yedeklerin ne olduğunu,
hangi maliyetle alındıklarını ve bir yedeğin geri yüklendiğinde kaynakla eşit olduğunun
nasıl kanıtlanacağını ele alıyor.
