---
title: 'Bozuk Erişim Denetimi'
source: 'https://academia.sh/tr/kurslar/guvenli-kodlama/bozuk-erisim-denetimi'
course: 'Güvenli Kodlama'
language: tr
updated: '2026-08-17T18:06:42+00:00'
license: 'CC BY-SA 4.0'
---

# Bozuk Erişim Denetimi

Yetki matrisinde nesne düzeyinde denetimi olmayan uç sayısının çıkarılması: on dört ucun beşi yalnız rol denetimi yapar, rol denetimini geçen yetmiş iki isteğin on dördü başkasının nesnesine ulaşır, öntanımlı ret üzerine kurulu merkezî kapı bu sayıyı sıfıra indirirken on meşru isteği durdurur ve ölçüt bildirmeden eklenen on beşinci uç dağıtık denetimde yanlış geçeni on yediye çıkarırken merkezî kapıda hiçbir yeni yol açmaz.

Önceki iki ders isteğin arkasındaki kimliği güvence altına aldı: kim olduğu sızdırılmadan
belirlendi, kimliğin taşıyıcısı doğru anlarda yenilendi ve doğru anlarda silindi. Kimliğin
doğru bilinmesi kararın yalnız yarısıdır. Bilinen bir kimlik bir uca istek yolladığında
ikinci soru sorulur ve bu soru uç başına sorulur.

Sorunun iki ayrı biçimi vardır ve karıştırıldığında hata doğar. Birincisi "bu rol bu eylemi
yapabilir mi?", ikincisi "bu asıl **bu nesneye** dokunabilir mi?". Yalnız birincisi sorulan
bir uç, kendi rolündeki herkesin bütün nesnelerini açar. **Nesne düzeyinde yetki atlaması**
budur: geçerli bir oturumla, doğru rolle, tek bir yol parametresi değiştirilerek yapılır.
Bunu bir servis üzerinde denemek **yazılı yetki ve tanımlı kapsam olmadan hem yasadışı hem
meslek dışıdır**; aşağıdaki ölçüm kendi yazdığımız matris üzerinde koşar.

## Matris, Asıl ve Nesne

Ölçümün girdisi bir yetki matrisidir: her uç için hangi rollerin çağırabildiği ve istenen
nesnenin istekle nasıl ilişkilendirildiği. İkinci alan iki kez yazılır — ucun **taşıması
gereken** ölçüt ve kodun bugün **gerçekten uyguladığı** ölçüt. İkisinin ayrı yazılması,
eksikliğin bir sayıya dönüşmesini sağlar.

Ölçüt üç biçimde yazılıyor. `sahip`, nesnenin doğrudan isteği yapana ait olmasıdır;
`atanan`, bir iş emrinin o görevliye verilmiş olmasıdır; `sube`, nesnenin isteği yapanla
aynı şubeye bağlı olmasıdır. Üçü de asıl ile nesne arasındaki bir **ilişkiyi** sınar — rol
gibi asılın tek başına taşıdığı bir nitelik değil. Yönetici rolü bu üç ölçütün hepsinde
şube sınırına indirgenir: yöneticinin ayrıcalığı bütün nesnelere erişmek değil, kendi
şubesinin nesnelerine erişmektir.

Aşağıdaki matris, asıl kümesi ve nesne kümesi bir **modeldir**: gerçek bir servis, gerçek
bir uç ve gerçek bir abone yoktur.

```js
// yetki/matris.mjs — abone portalinin yetki matrisi (model): gercek bir servis, gercek bir uc
// ve gercek bir abone yok. Roller, nesneler ve uclar veri olarak yazilmistir.

// KH9: her ucun iki ayri denetimi vardir — rol denetimi eylem turunu, olcut denetimi istenen
// nesnenin istegi yapanla iliskisini yetkilendirir. `dogru` o ucun tasimasi gereken olcuttur;
// `bildirilen` kodun bugun gercekten uyguladigi olcuttur (null: nesne denetimi yok).
export const UC = [
  { yol: "GET /faturalar/{id}",           tur: "fatura", rol: ["abone", "yonetici"], dogru: "sahip",  bildirilen: "sahip" },
  { yol: "GET /faturalar/{id}/kalemler",  tur: "fatura", rol: ["abone", "yonetici"], dogru: "sahip",  bildirilen: null },
  { yol: "POST /faturalar/{id}/itiraz",   tur: "fatura", rol: ["abone"],             dogru: "sahip",  bildirilen: null },
  { yol: "DELETE /faturalar/{id}",        tur: "fatura", rol: ["yonetici"],          dogru: "sube",   bildirilen: "sube" },
  { yol: "GET /okuma/{id}",               tur: "okuma",  rol: ["abone", "gorevli", "yonetici"], dogru: "sahip", bildirilen: "sahip" },
  { yol: "GET /okuma/{id}/gecmis",        tur: "okuma",  rol: ["abone", "gorevli"],  dogru: "sahip",  bildirilen: null },
  { yol: "POST /okuma/{id}/duzeltme",     tur: "okuma",  rol: ["gorevli", "yonetici"], dogru: "sube", bildirilen: "sube" },
  { yol: "GET /abone/{id}/profil",        tur: "abone",  rol: ["abone", "yonetici"], dogru: "sahip",  bildirilen: "sahip" },
  { yol: "PUT /abone/{id}/iletisim",      tur: "abone",  rol: ["abone"],             dogru: "sahip",  bildirilen: "sahip" },
  { yol: "POST /abone/{id}/tarife",       tur: "abone",  rol: ["yonetici"],          dogru: "sube",   bildirilen: "sube" },
  { yol: "GET /is-emri/{id}",             tur: "isemri", rol: ["gorevli", "yonetici"], dogru: "atanan", bildirilen: "atanan" },
  { yol: "POST /is-emri/{id}/kapat",      tur: "isemri", rol: ["gorevli", "yonetici"], dogru: "atanan", bildirilen: "atanan" },
  { yol: "POST /is-emri/{id}/not",        tur: "isemri", rol: ["gorevli"],           dogru: "atanan", bildirilen: null },
  { yol: "GET /rapor/{id}",               tur: "rapor",  rol: ["yonetici"],          dogru: "sube",   bildirilen: null },
];

// KH10: asil ve nesne kumeleri kurgudur; her nesnenin bir subesi, kimisinin sahibi ya da
// atanani vardir.
export const ASIL = [
  { kod: "a-4471", rol: "abone",    sube: "S-1" },
  { kod: "a-5120", rol: "abone",    sube: "S-2" },
  { kod: "g-31",   rol: "gorevli",  sube: "S-1" },
  { kod: "g-47",   rol: "gorevli",  sube: "S-2" },
  { kod: "y-08",   rol: "yonetici", sube: "S-1" },
];
export const NESNE = [
  { kod: "f-1", tur: "fatura", sahip: "a-4471", sube: "S-1" },
  { kod: "f-2", tur: "fatura", sahip: "a-5120", sube: "S-2" },
  { kod: "o-1", tur: "okuma",  sahip: "a-4471", sube: "S-1" },
  { kod: "o-2", tur: "okuma",  sahip: "a-5120", sube: "S-2" },
  { kod: "b-1", tur: "abone",  sahip: "a-4471", sube: "S-1" },
  { kod: "b-2", tur: "abone",  sahip: "a-5120", sube: "S-2" },
  { kod: "i-1", tur: "isemri", atanan: "g-31",  sube: "S-1" },
  { kod: "i-2", tur: "isemri", atanan: "g-47",  sube: "S-2" },
  { kod: "r-1", tur: "rapor",  sube: "S-1" },
  { kod: "r-2", tur: "rapor",  sube: "S-2" },
];

// KH11: olcut, asil ile nesne arasindaki iliskiyi sinar. Yonetici kendi subesinin nesnelerine
// erisir; sahiplik ve atanma dogrudan kod esitligidir.
export const olcut = (ad, asil, nesne) =>
  ad === "sube" ? nesne.sube === asil.sube
  : asil.rol === "yonetici" ? nesne.sube === asil.sube
  : ad === "sahip" ? nesne.sahip === asil.kod
  : nesne.atanan === asil.kod;
export const rolGecer = (uc, asil) => uc.rol.includes(asil.rol);
```

```js
// yetki/kapsama.mjs — kac uc nesne duzeyinde denetim yapiyor, denetimsiz uctan kac istek
// baskasinin nesnesine ulasiyor, merkezi kapi kacini kapatiyor ve kac mesru istegi durduruyor.
import { UC, ASIL, NESNE, olcut, rolGecer } from "./matris.mjs";
const yaz = (g, ...s) => console.log(s.map((v, i) =>
  (g[i] < 0 ? String(v).padEnd(-g[i]) : String(v).padStart(g[i]))).join(""));

// KH12: istek kumesi, rol denetimini gecen her (asil, uc, nesne) uclusudur. Uc kurulum ayni
// kume uzerinde kosar: dogru karar, dagitik denetim, merkezi kapi (olcut yoksa ontanimli ret).
const istekler = (kume) => {
  const l = [];
  for (const uc of kume) for (const a of ASIL) for (const n of NESNE)
    if (n.tur === uc.tur && rolGecer(uc, a)) l.push({ uc, a, n });
  return l;
};
const karar = (i, kurulum) => {
  if (kurulum === "dogru") return olcut(i.uc.dogru, i.a, i.n);
  if (i.uc.bildirilen) return olcut(i.uc.bildirilen, i.a, i.n);
  return kurulum === "dagitik";                       // merkezi kapida ontanimli ret
};
const say = (kume, kurulum, kosul) => istekler(kume).filter((i) => kosul(
  karar(i, kurulum), karar(i, "dogru"))).length;

const A = [-30, 6, 9, 12, 14];
console.log(`1. ${UC.length} uc: hangisi nesne duzeyinde denetim yapiyor`);
yaz(A, "uc", "rol", "dogru", "bildirilen", "yanlis gecen");
for (const uc of UC) {
  const y = istekler([uc]).filter((i) => karar(i, "dagitik") && !karar(i, "dogru")).length;
  yaz(A, uc.yol, uc.rol.length, uc.dogru, uc.bildirilen ?? "-", y || "-");
}
const olcutsuz = UC.filter((u) => !u.bildirilen);
console.log(`nesne duzeyinde denetimi olmayan uc: ${olcutsuz.length} / ${UC.length}`);

const B = [-38, 9, 9];
console.log("\n2. rol denetimini gecen istek kumesi");
yaz(B, "olcum", "istek", "pay %");
const T = istekler(UC).length;
const satir = (ad, n) => yaz(B, ad, n, ((n / T) * 100).toFixed(1));
satir("rol denetimini gecen istek", T);
satir("gecmesi gereken (dogru karar)", say(UC, "dogru", (k) => k));
satir("dagitik denetimde gecen", say(UC, "dagitik", (k) => k));
satir("dagitik: yanlis gecen istek", say(UC, "dagitik", (k, d) => k && !d));
satir("merkezi kapi: yanlis gecen", say(UC, "merkezi", (k, d) => k && !d));
satir("merkezi kapi: durdurulan mesru istek", say(UC, "merkezi", (k, d) => !k && d));

// 3. yeni uc eklendiginde: olcut bildirmeden eklenen bir uc
const YENI = { yol: "GET /fatura/{id}/odeme-plani", tur: "fatura", rol: ["abone", "yonetici"],
  dogru: "sahip", bildirilen: null };
const genis = [...UC, YENI];
const C = [-30, 6, 11, 14, 18];
console.log("\n3. olcut bildirmeyen yeni uc eklendiginde");
yaz(C, "kurulum", "uc", "olcutsuz", "yanlis gecen", "durdurulan mesru");
for (const [ad, kume, kurulum] of [
  ["bugunku dagitik denetim", UC, "dagitik"],
  ["merkezi kapi", UC, "merkezi"],
  ["yeni uc, dagitik denetim", genis, "dagitik"],
  ["yeni uc, merkezi kapi", genis, "merkezi"],
]) yaz(C, ad, kume.length, kume.filter((u) => !u.bildirilen).length,
  say(kume, kurulum, (k, d) => k && !d), say(kume, kurulum, (k, d) => !k && d));
```

```
1. 14 uc: hangisi nesne duzeyinde denetim yapiyor
uc                               rol    dogru  bildirilen  yanlis gecen
GET /faturalar/{id}                2    sahip       sahip             -
GET /faturalar/{id}/kalemler       2    sahip           -             3
POST /faturalar/{id}/itiraz        1    sahip           -             2
DELETE /faturalar/{id}             1     sube        sube             -
GET /okuma/{id}                    3    sahip       sahip             -
GET /okuma/{id}/gecmis             2    sahip           -             6
POST /okuma/{id}/duzeltme          2     sube        sube             -
GET /abone/{id}/profil             2    sahip       sahip             -
PUT /abone/{id}/iletisim           1    sahip       sahip             -
POST /abone/{id}/tarife            1     sube        sube             -
GET /is-emri/{id}                  2   atanan      atanan             -
POST /is-emri/{id}/kapat           2   atanan      atanan             -
POST /is-emri/{id}/not             1   atanan           -             2
GET /rapor/{id}                    1     sube           -             1
nesne duzeyinde denetimi olmayan uc: 5 / 14

2. rol denetimini gecen istek kumesi
olcum                                     istek    pay %
rol denetimini gecen istek                   72    100.0
gecmesi gereken (dogru karar)                32     44.4
dagitik denetimde gecen                      46     63.9
dagitik: yanlis gecen istek                  14     19.4
merkezi kapi: yanlis gecen                    0      0.0
merkezi kapi: durdurulan mesru istek         10     13.9

3. olcut bildirmeyen yeni uc eklendiginde
kurulum                           uc   olcutsuz  yanlis gecen  durdurulan mesru
bugunku dagitik denetim           14          5            14                 0
merkezi kapi                      14          5             0                10
yeni uc, dagitik denetim          15          6            17                 0
yeni uc, merkezi kapi             15          6             0                13
```

Sayılar **ölçüm** sınıfındadır; girdileri KH9–KH12'dir.

## Beş Uç, On Dört İstek

Birinci tablo envanteri verir: on dört ucun **beşi** nesne düzeyinde denetim yapmıyor.
Bunlar `bildirilen` sütununda çizgi taşıyan uçlardır ve her birinin yanında kaç isteğin
yanlış geçtiği yazılıdır.

Beş ucun dördü **alt kaynak** ya da **alt eylem**tir: fatura kalemleri, okuma geçmişi, iş
emri notu ve fatura itirazı. Üst kaynak için yazılmış ölçüt alt yola uygulanmış sayılır ve
soru orada bir daha sorulmaz. Beşincisi `GET /rapor/{id}`, tek rollü bir uçtur; tek rol
yetki denetiminin tamamı sanılmıştır.

Yanlış geçen istek sayıları uçlar arasında eşit değildir. `GET /okuma/{id}/gecmis` altı
istek sızdırıyor, `GET /rapor/{id}` yalnız bir. Fark rol sayısından gelir: okuma geçmişi iki
role açıktır ve iki rolün toplam dört asılı vardır, rapor ucu tek role ve tek asıla. Bir
ucun taşıdığı risk, ölçütünün eksik olmasıyla **rol kümesinin genişliğinin** çarpımıdır.
"Beş uç eksik" cümlesi bu farkı göstermez; istek sayısı gösterir.

Sıralama düzeltme sırasını da verir. Beş ucun tamamı aynı gün düzeltilemiyorsa, altı istek
sızdıran uç iki istek sızdırandan önce gelir; iki ucu düzeltmek sızıntının %64'ünü kapatır.
Bu sıralamanın kod incelemesinde görülemeyeceğine dikkat etmek gerekir: kodda beş uç da aynı
görünür, tek satır eksiktir. Farkı üreten şey kodun kendisi değil, ucun rol kümesi ile nesne
kümesinin kesişimidir.

## Yetmiş İki İsteğin On Dördü

İkinci tablo istek kümesini açar. Rol denetimini geçen istek sayısı **72**'dir; bunların
**32**'si geçmesi gereken isteklerdir (%44,4). Aradaki fark, rol denetiminin tek başına
neyi bıraktığını verir: rol denetimini geçen her iki istekten biri, doğru karara göre
reddedilmelidir.

Dağıtık denetimde geçen istek sayısı 46'dır. Bu sayı 32'den 14 fazladır ve o 14 istek,
**başkasının nesnesine ulaşan** isteklerdir — istek kümesinin %19,4'ü. Hepsi geçerli bir
oturumla, doğru rolle ve tek bir yol parametresi değiştirilerek yapılabilir.

Bu 14 isteğin ortak özelliği, sunucuda hiçbir hata üretmemeleridir. Yanıt 200'dür, kayıt
gerçekten vardır, sorgu doğru çalışır. Ölçülebilir tek iz istek kümesinin kendisidir: aynı
asıl, birbiri ardına, kendisine ait olmayan kimliklerle aynı uca gitmiştir. Denetim kaydı
bu deseni görebilir ama karar veremez; kararı verecek olan ölçüttür.

İstek kümesinin böyle üretilebilmesi ölçümün asıl kazancıdır. Küme elle yazılmadı; asıl,
uç ve nesne listelerinden **türetildi**. Aynı türetme bir sınama kümesi olarak da kullanılır:
her uç için "sahibi olmayan bir asılla çağır ve ret bekle" isteği kendiliğinden üretilir ve
uç sayısı arttıkça sınama sayısı da artar. Ölçüt bir veri olduğu için hem denetlenebilir hem
sınanabilir; bir `if` satırının içine gömülü olsaydı ikisi de yapılamazdı.

## Merkezî Kapı ve Bedeli

Merkezî kapı iki şeyi birleştirir: ölçüt uygulaması tek bir yerdedir ve ölçüt bildirmeyen uç
**öntanımlı olarak reddedilir**. İkinci tablonun son iki satırı bu kurulumun iki sütununu
verir. Yanlış geçen istek **0**'dır; durdurulan meşru istek **10**'dur — istek kümesinin
%13,9'u.

Bu on istek bir bedeldir ve yazılmalıdır. Öntanımlı ret, ölçütü eksik beş ucu tümüyle
kapatır; o uçların meşru kullanımı da durur. Fatura kalemlerini kendi faturası için isteyen
abone de 403 alır. Ama iki hata türü arasındaki fark gözlenebilirlikte yatar: durdurulan
meşru istek **ilk gün** bir hata kaydı üretir ve düzeltilir; yanlış geçen istek hiçbir kayıt
üretmez ve yıllarca fark edilmeyebilir. Öntanımlı ret, sessiz hatayı gürültülü hataya
çevirir.

Üçüncü tablo bunun sürekliliğini ölçer. Ölçüt bildirmeden eklenen on beşinci bir uç —
`GET /fatura/{id}/odeme-plani` — dağıtık denetimde yanlış geçeni 14'ten **17**'ye çıkarır.
Merkezî kapıda aynı uç yanlış geçeni 0'da bırakır ve durdurulan meşru isteği 10'dan 13'e
çıkarır. Kapsama sabittir; değişen şey görünür bedeldir.

Fark kalıbın gücünde değil, **varsayılanın yönündedir**. Dağıtık denetimde ölçütü yazmayı
unutmanın karşılığı açık bir uçtur; merkezî kapıda çalışmayan bir uçtur. İkisi de hatadır,
ama biri üretimde sessizce durur, öteki hemen bildirir. Merkezî kapının ölçülebilir katkısı
kapsama yüzdesi değil, **unutmanın sonucunu değiştirmesidir**.

## Özet

- Yetki sorusunun iki biçimi vardır: rol eylem türünü yetkilendirir, ölçüt istenen nesnenin
  isteği yapanla ilişkisini yetkilendirir. Yalnız birincisi sorulduğunda rol kümesindeki
  herkes bütün nesnelere ulaşır.
- On dört ucun beşi nesne düzeyinde denetim yapmıyor; dördü alt kaynak ya da alt eylem,
  biri tek rollü bir uç.
- Rol denetimini geçen 72 isteğin 32'si geçmelidir; dağıtık denetimde 46 istek geçiyor ve
  aradaki 14 istek (%19,4) başkasının nesnesine ulaşıyor.
- Bir ucun taşıdığı risk ölçüt eksikliğiyle rol kümesinin genişliğinin çarpımıdır: aynı
  eksiklik bir uçta 6, başka bir uçta 1 istek sızdırıyor.
- Öntanımlı ret üzerine kurulu merkezî kapı yanlış geçeni 0'a indirir ve 10 meşru isteği
  durdurur; on beşinci uç eklendiğinde yanlış geçen 0 kalır, dağıtık denetimde 17'ye çıkar.
- Merkezî kapının ölçülebilir katkısı, ölçütü unutmanın sonucunu sessiz bir açıktan
  gözlenebilir bir hataya çevirmesidir.

## Sonraki Adım

Bu ders yetki sorusunu tek bir istek üzerinde sordu: bu asıl, bu uçta, bu nesneye
dokunabilir mi? Üç sayı da tek istek varsayımına dayanıyor. Oysa bir sistemin kuralları yalnız
tek isteklerde değil, **istek dizilerinde** de yaşar. Bir indirim bir kez uygulanır, bir iade
bir kez alınır, bir kota bir dönemde bir kez tüketilir. Bu kuralların hiçbiri tek bir uçta
yazılı değildir; adımların sırasında yazılıdır. Sonraki ders akışları adım dizisi olarak
modeller ve sorar: adımların atlanabildiği ya da tekrarlanabildiği kaç yol var, durum
makinesi kaçını kapatıyor, kaçı dışarıda kalıyor.
