Ders 10 / 15
Kimlik Doğrulama ve Yetkilendirme Ayrımı
Aynı adım kümesi üzerinde iki denetim ayrı kapsamlara konur ve iki ayrı isteğe karşı ölçülür: sahte kimlikli istek ile doğrulanmış ama yetkisiz istek. Kimlik denetimini her adıma koymanın doğrulanmış-yetkisiz isteğe karşı kaç yol kapattığı ve yetkiyi yalnız veri katmanında sormanın açtığı yol sayılır.
İçindekiler
Önceki ders her adımda kimliği denetledi ve yol sayısını elli beşten yirmiye indirdi. Sorulan soru hep aynıydı: bu isteği kim gönderdi? Bir adımın geçilmesi için ise iki ayrı sorunun yanıtlanması gerekir. Kimlik doğrulama (authentication) isteği gönderenin kim olduğunu belirler; yetkilendirme (authorization) o kimliğin bu kalemde bu işlemi yapıp yapamayacağını belirler. İki soru farklıdır, farklı verilere bakar ve farklı yerlerde sorulabilir.
Kimlik ve Yetki kursunda bu ayrım akış ve belirteç düzeyinde ele alınmıştı. Burada ölçülen şey mekanizma değil, denetimin yanlış katmanda durmasının açtığı yoldur. Ölçüm iki ayrı isteğe karşı yapılıyor: kimliği sahte olan bir istek ve kimliği gerçek ama o adım için yetkisiz olan bir istek. İkincisi bu dersin asıl konusudur, çünkü çoğu denetim yalnız birincisini görür. Sahte kimlikli istek bir dış saldırganı, doğrulanmış ama yetkisiz istek ise ele geçirilmiş bir meşru kimliği ya da yanlış yapılandırılmış bir servisi temsil eder; ikinci durum ilkinden hem daha sık hem de daha zor görülür.
- SI22. Bir adım iki denetimden geçer. Kimlik denetimi kapsamdaysa isteğin kimliğinin geçerli olmasını, yetki denetimi kapsamdaysa o kimliğin adım için yetkili olmasını arar.
- SI23. Yetki kümesi meşru akış listesinden türetilir; bir kimlik, kendi akışlarının adımlarında ve ortak iç akış adımlarında yetkilidir.
- SI24. İki istek profili ayrı ayrı koşturulur. Sahte kimlikli istek kimlik denetiminden geçemez; doğrulanmış ama yetkisiz istek kimlik denetiminin tamamından geçer ve yalnız yetki denetimiyle durdurulabilir.
- SI25. Günlük denetim sayısı iki denetimin toplamıdır: bir adımda ikisi de yapılıyorsa iki işlem sayılır. Denetimlerin süresi ve gecikmesi modellenmiyor.
- SI26. Yetki denetimi her zaman doğru karar verir. Yetki kümesinin yanlış yazılmış olması, eskimiş kayıt ve devredilen oturum modellenmiyor; bunlar açılan yol sayısını büyütür.
İki Soru, İki Kapsam
Grafik ve meşru akış listesi değişmedi. Değişen tek şey, hangi adımda hangi sorunun sorulduğudur.
// ag.mjs — kurgusal bolgesel olcum aginin erisim grafigi ve mesru akislari (model) export const GIRIS = ['saha-uc', 'sube-agi', 'genel-uc', 'bakim-uc']; export const VARLIK = ['olcum-deposu', 'fatura-vt', 'abone-kayit', 'yapilandirma']; export const KENAR = [ ['saha-uc', 'toplayici'], ['saha-uc', 'is-emri'], ['sube-agi', 'toplayici'], ['sube-agi', 'is-emri'], ['sube-agi', 'yonetim'], ['genel-uc', 'toplayici'], ['bakim-uc', 'yonetim'], ['bakim-uc', 'kuyruk'], ['toplayici', 'kuyruk'], ['toplayici', 'olcum-deposu'], ['kuyruk', 'dogrulayici'], ['kuyruk', 'faturalama'], ['dogrulayici', 'olcum-deposu'], ['dogrulayici', 'fatura-vt'], ['faturalama', 'fatura-vt'], ['faturalama', 'abone-kayit'], ['is-emri', 'kuyruk'], ['is-emri', 'abone-kayit'], ['yonetim', 'toplayici'], ['yonetim', 'dogrulayici'], ['yonetim', 'is-emri'], ['yonetim', 'yapilandirma'], ]; // Mesru akis: gunluk kosan is; adim dizisi ayni grafigin kenarlarindan gecer. export const AKIS = [ ['saha-okuma', ['saha-uc', 'toplayici', 'kuyruk'], 1440], ['dogrulama', ['kuyruk', 'dogrulayici', 'olcum-deposu'], 1440], ['genel-okuma', ['genel-uc', 'toplayici', 'olcum-deposu'], 300], ['sube-sorgu', ['sube-agi', 'toplayici', 'olcum-deposu'], 210], ['fatura-yazimi', ['kuyruk', 'faturalama', 'fatura-vt'], 48], ['is-emri-acma', ['sube-agi', 'is-emri', 'abone-kayit'], 32], ['is-emri-kuyruk', ['sube-agi', 'is-emri', 'kuyruk'], 32], ['abone-guncelleme', ['faturalama', 'abone-kayit'], 6], ['yapilandirma-degisikligi', ['sube-agi', 'yonetim', 'yapilandirma'], 2], ['bakim-oturumu', ['bakim-uc', 'yonetim', 'toplayici'], 1], ['kuyruk-bakimi', ['bakim-uc', 'kuyruk'], 1], ['mutabakat', ['yonetim', 'dogrulayici', 'fatura-vt'], 1], ]; export const ad = (a, b) => `${a}>${b}`; export const adimlar = (d) => d.slice(0, -1).map((x, i) => ad(x, d[i + 1])); export function yollar(kapali = new Set()) { const komsu = new Map(); for (const [a, b] of KENAR) if (!kapali.has(ad(a, b))) komsu.set(a, [...(komsu.get(a) || []), b]); const s = []; const yuru = (d, y) => { if (VARLIK.includes(d)) return void s.push(y); for (const k of komsu.get(d) || []) if (!y.includes(k)) yuru(k, [...y, k]); }; for (const g of GIRIS) yuru(g, [g]); return s; } export const kesilen = (kapali) => AKIS.filter(([, d]) => adimlar(d).some((k) => kapali.has(k)));
// denetim.mjs — iki ayri soru: kimlik dogrulama ve yetkilendirme, ayri kapsamlarla import { KENAR, AKIS, GIRIS, VARLIK, ad, adimlar } from './ag.mjs'; export const KENAR_AD = KENAR.map(([a, b]) => ad(a, b)); const ORTAK = new Set(AKIS.filter(([, d]) => !GIRIS.includes(d[0])).flatMap(([, d]) => adimlar(d))); const kendi = (g) => AKIS.filter(([, d]) => d[0] === g).flatMap(([, d]) => adimlar(d)); // YETKI[g]: g kimliginin yetkili oldugu adimlar; mesru akis listesinden turetildi. export const YETKI = Object.fromEntries(GIRIS.map((g) => [g, new Set([...ORTAK, ...kendi(g)])])); export const CEVRE = KENAR_AD.filter((k) => GIRIS.includes(k.split('>')[0])); export const VARLIGA = KENAR_AD.filter((k) => VARLIK.includes(k.split('>')[1])); const komsu = new Map(); for (const [a, b] of KENAR) komsu.set(a, [...(komsu.get(a) || []), b]); // Bir adim iki ayri denetimden gecer; her denetimin kendi kapsami vardir. export function yol(g, kd, yd, kimlikGecerli) { const K = new Set(kd), Y = new Set(yd), out = []; const yuru = (d, y) => { if (VARLIK.includes(d)) return void out.push(y); for (const k of komsu.get(d) || []) { const e = ad(d, k); if (K.has(e) && !kimlikGecerli) continue; // kimlik dogrulama: sen kimsin if (Y.has(e) && !YETKI[g].has(e)) continue; // yetkilendirme: bunu yapabilir misin if (!y.includes(k)) yuru(k, [...y, k]); } }; yuru(g, [g]); return out; }
// kosum1.mjs — iki denetim farkli katmanlara konunca hangi istek durur, hangisi gecer import { AKIS, GIRIS, adimlar } from './ag.mjs'; import { KENAR_AD, CEVRE, VARLIGA, yol } from './denetim.mjs'; const SEMA = [['denetim-yok', [], []], ['kimlik-cevrede', CEVRE, []], ['kimlik-her-adimda', KENAR_AD, []], ['kimlik-cevre-yetki-veride', CEVRE, VARLIGA], ['kimlik-cevre-yetki-heryerde', CEVRE, KENAR_AD], ['yalniz-yetki-heryerde', [], KENAR_AD], ['ikisi-de-heryerde', KENAR_AD, KENAR_AD]]; const gunluk = AKIS.reduce((s, [, , n]) => s + n, 0); console.log('sema sahte dogrulanmis varlik gunluk denetim istek basi'); for (const [nm, kd, yd] of SEMA) { const sahte = GIRIS.reduce((s, g) => s + yol(g, kd, yd, false).length, 0); const dog = GIRIS.flatMap((g) => yol(g, kd, yd, true)); const K = new Set(kd), Y = new Set(yd); const den = AKIS.reduce((s, [, d, c]) => s + c * adimlar(d) .reduce((t, k) => t + (K.has(k) ? 1 : 0) + (Y.has(k) ? 1 : 0), 0), 0); console.log(`${nm.padEnd(29)}${String(sahte).padEnd(7)}${String(dog.length).padEnd(13)}` + `${String(new Set(dog.map((p) => p.at(-1))).size).padEnd(8)}${String(den).padEnd(16)}${(den / gunluk).toFixed(2)}`); }
sema sahte dogrulanmis varlik gunluk denetim istek basi denetim-yok 55 55 4 0 0.00 kimlik-cevrede 0 55 4 2018 0.57 kimlik-her-adimda 0 55 4 7019 2.00 kimlik-cevre-yetki-veride 0 50 4 4057 1.15 kimlik-cevre-yetki-heryerde 0 20 4 9037 2.57 yalniz-yetki-heryerde 20 20 4 7019 2.00 ikisi-de-heryerde 0 20 4 14038 4.00
İkinci ve üçüncü satır bu dersin ana bulgusudur. Kimlik denetimi çevreden her adıma genişletildiğinde günlük denetim iki bin on sekizden yedi bin on dokuza çıkıyor — istek başına sıfır virgül elli yediden tam iki ek adıma. Sahte kimlikli istek her iki satırda da sıfır yol buluyor; zaten çevrede duruyordu. Doğrulanmış ama yetkisiz istek ise her iki satırda da elli beş yolun tamamını kullanıyor. Kimlik denetimini üç buçuk katına çıkarmak, doğrulanmış bir isteğe karşı bir tek yol bile kapatmadı. Yanlış katmanda değil, yanlış sorunun katmanında yapılan bir genişletme budur.
Dördüncü satır uygulamada en sık görülen yerleşimdir: kimlik geçitte, yetki veri katmanında. Elli beş yolun beşi kapanıyor, ellisi açık kalıyor ve dört varlığın dördüne de erişiliyor. Yetkiyi yalnız son adımda sormanın nedeni anlaşılırdır — yetki kararı için gereken bilgi orada durur — ama sonucu, ara adımların hiç sorgulanmamasıdır. Doğrulanmış bir kimlik ara düğümlerin arasında serbestçe dolaşır ve yalnız varlığın kapısında bir soruyla karşılaşır.
Beşinci ve yedinci satırlar birlikte okunmalıdır. Yetkiyi her adıma koymak yolu yirmiye indiriyor; kimliği de her adıma koymak aynı yirmiyi veriyor. Fark yalnız maliyettedir: istek başına iki virgül elli yediye karşılık dört ek adım. Bir buçuk ek adım karşılığında kapanan yol sayısı sıfır. Kimlik doğrulamayı çevrede bırakıp yetkilendirmeyi yaymak, ikisini birden yaymakla aynı sonucu veriyor ve yaklaşık üçte bir daha ucuza mal oluyor.
Altıncı satır ayrımın öbür ucunu gösteriyor. Yetki her adımda sorulup kimlik hiç sorulmadığında sahte kimlikli istek yirmi yol buluyor. Yetki denetimi “bu kimlik bunu yapabilir mi” sorusunu yanıtlar; kimliğin gerçekten o kimlik olup olmadığını sormaz. İddia edilen kimlik doğru kabul edildiği anda, yetkilendirme o iddianın bütün ayrıcalıklarını verir. İki denetim birbirinin yerine geçmez: biri olmadan diğeri, açık kalan yolu farklı bir istek türüne devreder.
Yetki Son Adımda Sorulduğunda
Dördüncü satırın ellisi kimin elinde? Aynı ölçüm kimlik başına yapıldığında yetkilendirmenin neyi gördüğü ve neyi görmediği ayrışıyor.
// kosum2.mjs — yetki yalniz veri katmanindayken dogrulanmis-yetkisiz istek nereye ulasiyor import { GIRIS, VARLIK } from './ag.mjs'; import { CEVRE, VARLIGA, YETKI, yol } from './denetim.mjs'; console.log(`kimlik yetkili adim yol ${VARLIK.map((v) => v.slice(0, 8).padEnd(10)).join('')}`); const kapanan = []; for (const g of GIRIS) { const y = yol(g, CEVRE, VARLIGA, true), ulasan = new Set(y.map((p) => p.at(-1))); const acik = new Set(y.map((p) => p.join('>'))); kapanan.push(...yol(g, [], [], true).map((p) => p.join(' > ')).filter((p) => !acik.has(p.replaceAll(' > ', '>')))); console.log(`${g.padEnd(12)}${String(YETKI[g].size).padEnd(14)}${String(y.length).padEnd(5)}` + VARLIK.map((v) => (ulasan.has(v) ? 'evet' : 'hayir').padEnd(10)).join('')); } console.log(`\nveri katmani denetiminin kapattigi ${kapanan.length} yol:`); for (const p of kapanan) console.log(` ${p}`); const dar = GIRIS.flatMap((g) => yol(g, CEVRE, [...VARLIGA, ...CEVRE], true)); console.log(`\nyetki veri katmani + cevre oldugunda acik yol: ${dar.length}`);
kimlik yetkili adim yol olcum-de fatura-v abone-ka yapiland saha-uc 9 8 evet evet evet hayir sube-agi 14 23 evet evet evet evet genel-uc 9 5 evet evet evet hayir bakim-uc 10 14 evet evet evet hayir veri katmani denetiminin kapattigi 5 yol: saha-uc > toplayici > olcum-deposu saha-uc > is-emri > abone-kayit bakim-uc > yonetim > toplayici > olcum-deposu bakim-uc > yonetim > is-emri > abone-kayit bakim-uc > yonetim > yapilandirma yetki veri katmani + cevre oldugunda acik yol: 46
Şube ağı satırı yetkilendirmenin veri katmanında ne kadar kör olduğunu gösteriyor. Yirmi üç yolun yirmi üçü açık; bir tek yol kapanmadı. Nedeni yetki kümesinin şeklidir: şube ağı kimliği kendi meşru işi için dört varlığın dördüne de bir adım yetkisi taşıyor — ölçüm deposunu okuyor, iş emri açarken abone kaydına yazıyor, yapılandırma değişikliği yapıyor ve iç akışlar üzerinden fatura veritabanına yazıyor. Veri katmanındaki denetim yalnız son adıma baktığı için, o son adım yetkili olduğunda oraya nasıl gelindiği hiç sorulmuyor. Yetkili adım sütunu bu sonucun göstergesidir: sahiplik kümesi genişledikçe veri katmanı denetiminin durdurabileceği yol azalır ve on dört adımda sıfıra iner. En geniş yetkiye sahip kimlik, en son adımda denetlenen bir sistemde hiç denetlenmemiş sayılır.
Genel uç en dar kimliktir ve yine de beş yolun beşinde ilerliyor; saha ucu ondan sekize, bakım ucu on yediden on dörde iniyor. Kapanan beş yol listelenmiş durumda ve hepsinin ortak bir özelliği var: tamamı iki ya da üç adımlık kısa yollar. Uzun yolların hiçbiri kapanmıyor.
Nedeni son adımın kime ait olduğudur. Uzun yollar doğrulayıcı ya da faturalama üzerinden varlığa girer; bu iki servisin varlığa yazan adımları iç akışlara aittir ve iç akış adımları bütün kimliklerce ortak kullanılır. Veri katmanındaki denetim son adıma baktığında karşısında hep yetkili bir adım bulur. Kısa yollar ise varlığa doğrudan girer ve son adımları belirli bir kimliğe aittir; ancak orada bir uyuşmazlık görünür. Yolu uzatmak, veri katmanındaki denetimden kaçmanın yoludur — ve bu, denetimin bir eksiği değil, konduğu yerin sonucudur.
Son satır ara bir seçeneği ölçüyor. Yetkilendirme veri katmanına ek olarak çevreye de konduğunda açık yol elliden kırk altıya iniyor. Dört yol daha kapandı — sekiz adımlık bir denetim eklemenin karşılığı bu. Yetkilendirmeyi genişletmek yolu doğrusal biçimde kapatmıyor; kapanma denetimin hangi adımda durduğuna bağlı ve en çok yolu ortadaki adımlar taşıyor. Yetkiyi uçlara koymak, yolun uçlarını kesip ortasını açık bırakmaktır; ilk tablodaki yirmi sayısına ancak ortadaki adımlar da sorguya dahil edildiğinde inilir.
İki tablo birlikte bir yerleştirme kuralı veriyor. Kimlik doğrulama tek bir yerde yapılabilir, çünkü yanıtı yol boyunca değişmez: bir istek kimse sonuna kadar odur. Yetkilendirme ise her adımda yeniden sorulmalıdır, çünkü yanıtı adımdan adıma değişir: aynı kimlik bir adımda yetkili, bir sonrakinde değildir. Bu asimetri iki denetimin neden farklı katmanlara ait olduğunu açıklıyor ve tablodaki maliyet farkını da haklı çıkarıyor — kimliği çevrede bırakıp yetkiyi yaymak, istek başına dört yerine iki virgül elli yedi ek adımla aynı yirmi yolu verdi.
Ölçümün bir sınırı da burada yazılmalıdır. Model yetki kümesinin doğru olduğunu ve her adımda doğru değerlendirildiğini kabul etti. Gerçekte yetki kararını ara bir adımda vermek, o adımın kararı verecek bilgiye sahip olmasını gerektirir: hangi kimliğin adına çalışıldığı, hangi kalemin istendiği ve hangi eylemin yapıldığı. Bu bilgi yol boyunca taşınmıyorsa ara adımda yetki sorulamaz — sorulsa da yanıtı “bilmiyorum” olur ve bu yanıt geçirmeye dönüşür. Önceki dersteki ortak adım sorunu ile buradaki ara adım sorunu aynı eksikliğin iki yüzüdür: bir isteğin kimin adına ve ne için yapıldığı, adımlar arasında taşınmıyorsa hiçbir ara denetim doğru karar veremez. Dolayısıyla tablodaki yirmi sayısı bir hedef değil, akışlar bu bilgiyi taşıdığında ulaşılabilir bir alt sınırdır.
Özet
- Bir adımın geçilmesi iki ayrı soruya bağlıdır ve iki soru farklı istek türlerini durdurur: kimlik doğrulama sahte kimliği, yetkilendirme doğrulanmış ama yetkisiz isteği.
- Kimlik denetimini çevreden her adıma genişletmek günlük denetimi 2.018’den 7.019’a çıkarıyor (istek başına 0,57’den 2,00’ye) ve doğrulanmış-yetkisiz isteğe karşı 0 yol kapatıyor.
- Kimlik geçitte, yetki veri katmanında yerleşiminde 55 yolun 50’si açık kalıyor ve 4 varlığın dördüne de erişiliyor. Son adım yetkiliyse oraya nasıl gelindiği hiç sorulmuyor.
- Şube ağı kimliği için veri katmanı denetimi 23 yolun hiçbirini kapatmıyor; kendi meşru işi gereği dört varlığın dördünde de bir adım yetkisi taşıyor.
- Yetkiyi her adıma koymak yolu 20’ye indiriyor (istek başına 2,57). Kimliği de her adıma koymak aynı 20’yi veriyor ama istek başına 4,00’e çıkıyor: 1,43 ek adım karşılığında 0 yol.
- Yetki her adımda sorulup kimlik hiç sorulmadığında sahte kimlikli istek 20 yol buluyor. İki denetim birbirinin yerine geçmez; biri eksikse açık yol başka bir istek türüne devredilir.
Sonraki Adım
Bu ders iki denetimi ayırdı ve her birinin hangi isteği durdurduğunu saydı. Bütün şemalarda ortak olan bir varsayım vardı: kapsam listesi doğru yazılmış, kapsamda olması gereken her adım kapsamda. Gerçekte bu liste elle yazılır, ağ değiştikçe güncellenir ve bir kalem unutulur. Unutulan kalemin ne olacağı denetimin varsayılanına bağlıdır: kapsam dışı kalan adım geçiriyorsa unutmak bir yol açar, durduruyorsa unutmak bir işi durdurur. Sonraki dersin ölçtüğü şey budur: varsayılan açıkken ve kapalıyken yol sayısı ne oluyor, tek bir kalemi unutmanın bedeli kaç yol ve kaç duran iş ediyor, ve bu iki hatanın hangisi kendini gösteriyor.
İlerlemeni kaydetmek ve not almak için Giriş yap
Notlarım
Not almak için giriş yapmalısın.