Ders 10 / 17
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.
İçindekiler
Ö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.
// 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);
// 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 eylemtir: 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.
İlerlemeni kaydetmek ve not almak için Giriş yap
Notlarım
Not almak için giriş yapmalısın.