---
title: 'Nesne Düzeyi Yetki Denetimi'
source: 'https://academia.sh/tr/kurslar/kimlik-ve-yetki/nesne-duzeyi-yetki-denetimi'
course: 'Kimlik Doğrulama ve Yetkilendirme'
language: tr
updated: '2026-08-17T18:06:48+00:00'
license: 'CC BY-SA 4.0'
---

# Nesne Düzeyi Yetki Denetimi

Rol, kapsam ve kiracı denetimlerinden sonra kalan sahiplik sınırı, denetimin sorgu içine konmasıyla dışında bırakılmasının farkı, yanıt kodundan sızan varlık bilgisi ve sahiplik ölçütünün taranabilir hâle getirilmesi.

Kiracı sınırı, isteğin hangi kümeye dokunabileceğini belirledi. Küme içinde ise hâlâ tek
tek nesneler vardır. Aynı kütüphanenin iki üyesi aynı rolü taşır, aynı kapsamlı belirteci
kullanır ve aynı kiracıya aittir; buna rağmen biri diğerinin ödünç kaydını görmemelidir.

Bu son sınır, adres çubuğunda bir kimlik değiştirildiğinde sınanır. Rol denetimi geçilir,
kapsam denetimi geçilir, kiracı denetimi geçilir — ve istek yine de reddedilmelidir, çünkü
istenen **nesne** isteği yapana ait değildir.

## Üç Gerçekleştirim, Aynı Uç Nokta

Sahiplik denetimi üç yerde yapılabilir: hiç yapılmaz, kayıt çekildikten sonra yapılır ya da
sorgunun kendisine konur. Aşağıdaki hesap üçünü aynı istek kümesiyle çalıştırır.

```bash
cat > nesne.mjs <<'EOF'
// nesne.mjs — nesne duzeyi yetki denetimi: sahiplik sorgunun icinde mi disinda mi
import { DatabaseSync } from "node:sqlite";
import { randomUUID } from "node:crypto";

const db = new DatabaseSync(":memory:");
db.exec(`
  CREATE TABLE odunc (odunc_id TEXT PRIMARY KEY, uye_id TEXT NOT NULL, isbn TEXT NOT NULL,
                      durum TEXT NOT NULL, not_metni TEXT);
  INSERT INTO odunc VALUES
    ('O-1','U-1001','978-0201896831','ACIK','Kapak zedeli teslim alindi'),
    ('O-2','U-1001','978-0262033848','KAPALI',NULL),
    ('O-3','U-1002','978-0131103627','ACIK','Ikinci uyari gonderildi');
`);

// Uc gerceklestirim. Ucu de ayni istegi karsilar: GET /oduncler/{id}
const uclar = {
  denetimsiz: (ctx, id) => db.prepare("SELECT * FROM odunc WHERE odunc_id = ?").all(id),
  cekSonraDenetle: (ctx, id) => {
    const satir = db.prepare("SELECT * FROM odunc WHERE odunc_id = ?").all(id)[0];
    if (!satir) return { durum: 404, govde: null };
    if (satir.uye_id !== ctx.uye) return { durum: 403, govde: { hata: "bu kayit size ait degil" } };
    return { durum: 200, govde: satir };
  },
  sorguDaDenetle: (ctx, id) => {
    const satir = db.prepare("SELECT * FROM odunc WHERE odunc_id = ? AND uye_id = ?").all(id, ctx.uye)[0];
    return satir ? { durum: 200, govde: satir } : { durum: 404, govde: null };
  },
};

const ctx = { uye: "U-1001" };          // istegi yapan uye
const dolgu = (s, n) => String(s).padEnd(n);

console.log("gerceklestirim    istenen  sonuc                       baskasinin kaydi gorundu mu");
for (const id of ["O-1", "O-3", "O-9"]) {
  const ham = uclar.denetimsiz(ctx, id);
  const sahip = ham[0] && ham[0].uye_id !== ctx.uye;
  console.log(`${dolgu("denetimsiz", 17)} ${dolgu(id, 8)} ${dolgu(ham.length ? "200 kayit dondu" : "bos", 27)} ${sahip ? "EVET" : "hayir"}`);
}
for (const [ad, f] of [["cek-sonra-denetle", uclar.cekSonraDenetle], ["sorguda-denetle", uclar.sorguDaDenetle]]) {
  for (const id of ["O-1", "O-3", "O-9"]) {
    const y = f(ctx, id);
    console.log(`${dolgu(ad, 17)} ${dolgu(id, 8)} ${dolgu(y.durum + (y.govde ? " kayit dondu" : " govdesiz"), 27)} hayir`);
  }
}

// Varlik sizintisi: iki gerceklestirimin yanit kodlari baskasinin kaydini ele veriyor mu?
console.log("\nyanit kodlarindan cikarilabilen bilgi");
for (const [ad, f] of [["cek-sonra-denetle", uclar.cekSonraDenetle], ["sorguda-denetle", uclar.sorguDaDenetle]]) {
  const varOlanBaskasinin = f(ctx, "O-3").durum;
  const hicYok = f(ctx, "O-9").durum;
  console.log(`  ${dolgu(ad, 18)} baskasinin kaydi: ${varOlanBaskasinin}   olmayan kayit: ${hicYok}` +
    (varOlanBaskasinin !== hicYok ? "   -> kaydin varligi sizdi" : "   -> ikisi ayirt edilemiyor"));
}

// Tahmin edilemez kimlik yetkilendirme degildir.
const rastgele = randomUUID();
console.log("\ntahmin edilemez kimlik denemesi");
console.log(`  uretilen kimlik: ${rastgele.length} karakter, sozlukten tahmin edilemez`);
console.log("  ama kimlik ele gecerse (kayit, gunluk, paylasilan baglanti) denetimsiz uc nokta yine kaydi doner.");
console.log(`  denetimsiz uc nokta O-3 icin: ${uclar.denetimsiz(ctx, "O-3").length} kayit`);

// Uc nokta taramasi: hangi uc noktalar sahiplik olcutunu bildiriyor?
const UC_NOKTALAR = [
  { yol: "GET /oduncler/{id}",            olcut: "uye_id = :ozne" },
  { yol: "DELETE /oduncler/{id}",         olcut: "uye_id = :ozne" },
  { yol: "GET /oduncler/{id}/not",        olcut: null },
  { yol: "GET /uyeler/{id}/cezalar",      olcut: "uye_id = :ozne" },
  { yol: "POST /oduncler/{id}/uzat",      olcut: null },
  { yol: "GET /raporlar/gecikme",         olcut: "rol = gorevli" },
];
console.log("\nuc nokta                       sahiplik olcutu     bulgu");
let eksik = 0;
for (const u of UC_NOKTALAR) {
  const sorunlu = u.olcut === null;
  if (sorunlu) eksik++;
  console.log(`${dolgu(u.yol, 30)} ${dolgu(u.olcut ?? "-", 19)} ${sorunlu ? "OLCUT BILDIRILMEMIS" : "-"}`);
}
console.log(`bildirilmemis uc nokta: ${eksik} / ${UC_NOKTALAR.length}`);
EOF
node nesne.mjs
```

```text
gerceklestirim    istenen  sonuc                       baskasinin kaydi gorundu mu
denetimsiz        O-1      200 kayit dondu             hayir
denetimsiz        O-3      200 kayit dondu             EVET
denetimsiz        O-9      bos                         hayir
cek-sonra-denetle O-1      200 kayit dondu             hayir
cek-sonra-denetle O-3      403 kayit dondu             hayir
cek-sonra-denetle O-9      404 govdesiz                hayir
sorguda-denetle   O-1      200 kayit dondu             hayir
sorguda-denetle   O-3      404 govdesiz                hayir
sorguda-denetle   O-9      404 govdesiz                hayir

yanit kodlarindan cikarilabilen bilgi
  cek-sonra-denetle  baskasinin kaydi: 403   olmayan kayit: 404   -> kaydin varligi sizdi
  sorguda-denetle    baskasinin kaydi: 404   olmayan kayit: 404   -> ikisi ayirt edilemiyor

tahmin edilemez kimlik denemesi
  uretilen kimlik: 36 karakter, sozlukten tahmin edilemez
  ama kimlik ele gecerse (kayit, gunluk, paylasilan baglanti) denetimsiz uc nokta yine kaydi doner.
  denetimsiz uc nokta O-3 icin: 1 kayit

uc nokta                       sahiplik olcutu     bulgu
GET /oduncler/{id}             uye_id = :ozne      -
DELETE /oduncler/{id}          uye_id = :ozne      -
GET /oduncler/{id}/not         -                   OLCUT BILDIRILMEMIS
GET /uyeler/{id}/cezalar       uye_id = :ozne      -
POST /oduncler/{id}/uzat       -                   OLCUT BILDIRILMEMIS
GET /raporlar/gecikme          rol = gorevli       -
bildirilmemis uc nokta: 2 / 6
```

## Denetimsiz Uç Noktanın Gözlenebilir Sonucu

İlk bölümdeki tabloda denetimsiz gerçekleştirim, başkasına ait `O-3` kaydını olduğu gibi
döndürüyor. İstek geçerli bir belirteçle geldi, üye kendi hesabındaydı, yalnız yol
parametresi değişti. Sızan şey bir ödünç kaydı; içinde başka bir üyenin okuma geçmişi ve
kaydın not alanı var.

Bu kusur sınıfı, uygulamanın hiçbir katmanında hata üretmediği için sessizdir: günlükte
başarılı bir istek görünür, izleme panosunda hata oranı değişmez. Ancak yakalanması da
kolaydır — her uç nokta için "bu kaydın isteği yapanla ilişkisi nedir" sorusunun yazılı bir
yanıtı varsa, yanıtı olmayan uç noktalar listelenebilir.

## Denetimin Yeri Yanıtı Değiştirir

İkinci bölüm iki doğru gerçekleştirimi ayırıyor. Kayıt çekildikten sonra denetleyen sürüm,
başkasının kaydı için `403`, olmayan kayıt için `404` döndürüyor. İkisi farklı olduğu için
bir gözlemci, denemediği bir kimliğin **var olduğunu** öğrenebilir: `403` "bu kayıt var ama
senin değil" demektir.

Sorgunun içinde denetleyen sürümde iki durum aynı yanıtı üretir. Kayıt ya isteği yapanın
kümesindedir ya da yoktur; ikisi arasında ayrım yapılmaz. Bu, varlık bilgisinin
sızmamasını sağlar ve ek bir yararı vardır: denetim unutulamaz, çünkü ölçüt sorgunun
parçasıdır. Çek-sonra-denetle kalıbında `if` satırını silmek yeterlidir; sorguda denetleme
kalıbında aynı hatayı yapmak için sorguyu yeniden yazmak gerekir.

Seçim her zaman `404` yönünde değildir. Kullanıcının erişimi olmadığını **bilmesi gereken**
durumlarda — bir ekip üyesinin başka bir ekibin panosuna gitmesi gibi — `403` daha
yardımcıdır ve varlık bilgisi zaten paylaşılan bir bilgidir. Ölçüt şudur: kaydın varlığı
isteği yapan için gizli bir bilgi mi?

## Tahmin Edilemez Kimlik Bir Yetki Denetimi Değildir

Üçüncü bölüm sık rastlanan bir yanılgıyı ölçüyor. Sıralı sayı yerine tahmin edilemez bir
kimlik kullanmak, kimlikleri **keşfetmeyi** zorlaştırır; kaydı **korumaz**. Kimlik bir
kayıt bağlantısında, tarayıcı geçmişinde, sunucu günlüğünde ya da paylaşılan bir bağlantıda
ele geçtiğinde denetimsiz uç nokta kaydı yine döndürür — çıktının son satırı bunu gösteriyor.

Tahmin edilemez kimliğin yeri savunmanın **derinliğidir**, yerine geçmesi değil. Kimlik
tasarımı toplu keşfi engeller; yetki denetimi tekil erişimi engeller. İkisi farklı işler
yapar ve biri diğerini gereksizleştirmez.

## Ölçütü Yazılı Hâle Getirmek

Son bölüm uç noktaları tarıyor: her uç nokta için sahiplik ölçütü bildirilmiş mi? Altı uç
noktanın ikisi ölçüt bildirmiyor ve ikisi de alt kaynak: bir ödünç kaydının notu ve uzatma
eylemi. Alt kaynaklar bu kusurun en sık göründüğü yerdir, çünkü üst kaynak için yazılmış
denetimin alt yola da uygulandığı varsayılır.

Ölçütün yazılı olması iki şey sağlar. Yeni bir uç nokta eklendiğinde ölçüt alanı boş
kalırsa tarama bunu bulur — kod incelemesinde gözden kaçan şey listede görünür. İkincisi,
ölçüt bir veri olduğu için sınanabilir: her uç nokta için "sahibi olmayan bir özneyle çağır
ve boş sonuç bekle" testi kendiliğinden üretilebilir.

Bu kursta kurulan bütün modeller — rol, öznitelik, ilişki, politika, kapsam, kiracı —
kararı **nesneden bağımsız** verir. Nesne düzeyi denetim, o kararın son adımıdır ve
atlandığında diğerlerinin hepsi geçilmiş olur. Bu yüzden yetki denetimi tek bir yerde değil,
isteğin yolu boyunca katman katman yapılır.

## Özet

- Nesne düzeyi denetim, rol, kapsam ve kiracı denetimlerinin hepsi geçildikten sonra kalan
  son sınırdır: istenen kaydın isteği yapanla ilişkisi.
- Denetimsiz uç nokta hata üretmeden başkasının kaydını döndürür; modelde tek bir yol
  parametresi değişikliği yeterli oldu.
- Sahiplik ölçütü sorgunun içine konduğunda hem unutulması zorlaşır hem de varlık bilgisi
  sızmaz; çek-sonra-denetle kalıbında `403` ile `404` ayrımı kaydın varlığını ele verir.
- Tahmin edilemez kimlik keşfi zorlaştırır, erişimi yetkilendirmez; kimlik ele geçtiğinde
  denetimsiz uç nokta kaydı yine döndürür.
- Her uç nokta için sahiplik ölçütünün yazılı olması taranabilir ve sınanabilir kılar;
  modelde ölçütü bildirilmemiş iki uç noktanın ikisi de alt kaynaktı.

## Kurs Kapanışı

Bu kurs iki soruyu birbirinden ayırarak başladı: **kim olduğun** ve **ne yapabildiğin**.
Kimlik Doğrulama Akışları konusu birinci soruyu ele aldı; temel şemadan oturum ve belirteç
tabanlı akışlara, imza doğrulamanın ayrıntısına, yenileme belirteçlerinin dönüşümlü
kullanımına, yetki devri protokollerine ve çok etmenli doğrulamaya kadar her akışın hangi
sorunu çözdüğünü ve nerede kırıldığını gösterdi. Kimlik Bilgisi Güvenliği konusu
kimlik bilgisinin saklanmasını ölçülebilir kurallara bağladı: yavaş karma parametreleri,
tuzun ve biberin ayrı işleri, sıfırlama akışının yüzeyi ve oturumun ömrü. Yetkilendirme
Modelleri konusu ikinci soruyu dört modelde kurdu, kapsamla istemci yetkisini daralttı,
kiracı sınırını sorguya taşıdı ve bu dersle nesne düzeyine indi.

Kurs boyunca değişmeyen üç ölçüt vardı. Karar bir yerde **verilir**, başka bir yerde
**uygulanır**; ikisinin ayrılması denetimi mümkün kılar. Reddin nedeni ayırt edilebilir
olmalıdır, ama ayrıntısı isteği yapana sızmamalıdır. Ve her denetim, unutulduğunda
gözlenebilir bir sonuç üretmelidir — sızan kayıt sayısı, açılan uç nokta sayısı, ayırt
edilebilen yanıt kodu.

Sıradaki kurs, **Veri Erişim Katmanı ve İş Mantığı**, bu kararların altındaki katmana
iner. Yetki denetiminin sorguya taşınması bu kursta bir güvenlik gereği olarak çıktı;
orada aynı sorgu bir başarım ve tasarım sorusu hâline gelir: veri erişimi iş mantığından
nasıl ayrılır, işlem sınırı nereye çizilir ve aynı veriye giden yolların maliyeti nasıl
ölçülür?
