İçeriğe geç
academia.sh

Ders 14 / 16

Kimlik Doğrulama Günlükleri

Bir günlük 1.168 satırlık kurgu kimlik doğrulama kümesi ayrıştırılır ve altı başarısızlık kümesi eşik kurallarına karşı ölçülür: hesap başına eşik 216 kampanya olayının 206'sını kaçırıyor, 5 yanlış pozitif üretiyor ve 9 meşru girişi durduruyor; pencereyi 24 saate açmak iki kampanyayı da yakalıyor ama 70 hesabı kilitleyip 49 meşru girişi kesiyor. Püskürtme hesap başına en çok 2 deneme yaptığı için hiçbir eşikte görünmüyor; bölge ekseninde sayan kural onu ayırıyor, çünkü en büyük meşru toplu başarısızlık 62 hesapta kalıyor.

İçindekiler

Bir önceki dersin kapsam tablosunda kimlik doğrulama günlüğü on iki tutunma noktası türünün hiçbirini adıyla yazmıyordu. O kaynağın işi kalem izlemek değildir: bir tutunma noktasının kurulabilmesi için önce bir oturumun açılması gerekir ve kimlik doğrulama günlüğü tam olarak o adımı görür. Kapattığı nokta sayısı sıfırdır; görünür kıldığı şey noktaların öncesidir.

Bu ders o günlüğü tek başına ele alır. Soru bir uyarı kuralının nasıl yazılacağı değil, seçilen eşiğin ne kaçırdığı ve karşılığında kaç meşru işi durdurduğudur. Aşağıdaki günlük kümesi bir modeldir ve bölgesel ölçüm ağı kurgudur; hesap adları, makine adları ve bölge adları uydurmadır. Bir hesap kümesine parola denemesi, yazılı yetki ve tanımlı kapsam olmadan hem yasadışı hem meslek dışıdır; burada denemenin kendisi değil, geride bıraktığı kayıt ölçülür.

  • SG6. Günlük kümesi bir günü kapsar: 96 personel hesabı, 14 servis kimliği, beş ağ bölgesi. Satırlar metindir; alanlar düzenli ifadeyle çıkarılır.
  • SG7. Modelin bildiği küme etiketi günlük satırına yazılmaz. Ayrıştırıcı onu göremez; kuralların yalnız satırlardaki alanları vardır.
  • SG8. Altı küme vardır. Dördü meşrudur: yazım hatası, unutulmuş parola, kimliği eskimiş servis hesabı, sunucu tarafı kimlik ayarı değişikliği. İkisi kampanyadır: odaklı deneme ve püskürtme.
  • SG9. Kural 1 hesap başına başarısızlık, kural 2 bölge başına ayrı hesap sayar. İkisi de kayan pencere kullanır; bir anahtar için yalnız ilk geçiş uyarı üretir.
  • SG10. Eşik kilitlemeye bağlıdır: eşiği geçen hesap günün kalanında giremez. Durdurulan giriş sayısı bu varsayımdan çıkar.

Günlüğü Ayrıştırmak

// giris.mjs — kurgu kimlik dogrulama gunlugu uretilir ve ayristirilir. MODELDIR.
// Gercek kurum, gercek hesap ve gercek adres yoktur; bolge adlari kurgudur.
// Uretec kendi yazilmistir; tohum asagida gorunur.
export const TOHUM = 20260314;
const uretec = (t) => { let s = t >>> 0;
  return () => (s = (s * 1664525 + 1013904223) >>> 0) / 4294967296; };
const r = uretec(TOHUM);
const tam = (n) => Math.floor(r() * n);
const saat = (s) => [s / 3600, (s / 60) % 60, s % 60]
  .map((v) => String(Math.floor(v)).padStart(2, "0")).join(":");

export const HESAP = Array.from({ length: 96 }, (_, i) => `sh-${101 + i}`);
export const SERVIS = Array.from({ length: 14 }, (_, i) => `sv-${201 + i}`);
export const BOLGE = ["sube-ag", "saha-vpn", "toplayici-ag", "yonetim-ag", "dis-erisim"];

// Ham kayit: [saniye, makine, sonuc, hesap, bolge, etiket]. Etiket modelin bildigi dogrudur
// ve gunluk satirina YAZILMAZ; ayristirma onu goremez.
const ham = [];
const ekle = (s, mak, sonuc, hesap, bolge, etiket) =>
  ham.push([s, mak, sonuc, hesap, bolge, etiket]);

// 1) Vardiya basinda normal giris; bir bolumunde yazim hatasi.
for (const [i, h] of HESAP.entries()) {
  const b = BOLGE[i % 3], mak = `uc-${String(1 + (i % 268)).padStart(3, "0")}`;
  let t = 25200 + tam(7200);                       // 07:00 - 09:00 arasi
  if (r() < 0.22) for (let k = 0, n = 1 + tam(2); k < n; k++)
    ekle(t += 20 + tam(40), mak, "basarisiz", h, b, "yazim-hatasi");
  ekle(t + 15, mak, "basarili", h, b, "yazim-hatasi");
  for (let k = 0, n = tam(3); k < n; k++)
    ekle(36000 + tam(28800), mak, "basarili", h, b, "yazim-hatasi");
}
// 2) Parolasini unutan uc hesap: yogun basarisizlik, sonra sifirlama ve giris.
for (const h of [HESAP[7], HESAP[41], HESAP[70]]) {
  let t = 27000 + tam(9000);
  const n = 9 + tam(8);
  for (let k = 0; k < n; k++)
    ekle(t += 30 + tam(90), "uc-114", "basarisiz", h, "saha-vpn", "unutulmus-parola");
  ekle(t + 2400, "uc-114", "basarili", h, "saha-vpn", "unutulmus-parola");
}
// 3) Kimligi eskimis iki servis hesabi: gun boyu duzenli yeniden deneme.
for (const [j, h] of [SERVIS[3], SERVIS[9]].entries())
  for (let t = 600 + j * 130; t < 86400; t += 300)
    ekle(t, "uc-207", "basarisiz", h, "toplayici-ag", "eskimis-servis-kimligi");
// 4) Tek hesaba odakli deneme: uc saat boyunca ayni hesap.
for (let k = 0, t = 68400; k < 40; k++)
  ekle(t += 240 + tam(60), "uc-018", "basarisiz", HESAP[92], "dis-erisim", "odakli-deneme");
// 5) Puskurtme: 88 hesabin her birine iki deneme, elli dakikalik pencere.
for (const [j, h] of HESAP.slice(0, 88).entries()) {
  ekle(48000 + j * 17, "uc-018", "basarisiz", h, "dis-erisim", "puskurtme");
  ekle(49500 + j * 17, "uc-018", "basarisiz", h, "dis-erisim", "puskurtme");
}
ekle(51100, "uc-018", "basarili", HESAP[63], "dis-erisim", "puskurtme");
// 6) Sunucu tarafi kimlik ayari degisikligi: 62 sube hesabi bir kez basarisiz, sonra girer.
for (const [j, h] of HESAP.slice(20, 82).entries()) {
  ekle(36000 + j * 19, "uc-061", "basarisiz", h, "sube-ag", "ayar-degisikligi");
  ekle(36300 + j * 19, "uc-061", "basarili", h, "sube-ag", "ayar-degisikligi");
}

ham.sort((a, b) => a[0] - b[0]);
export const SATIR = ham.map(([s, mak, sonuc, hesap, bolge]) =>
  `2026-03-14T${saat(s)} ${mak} kimlik-dogrulama sonuc=${sonuc} hesap=${hesap} ` +
  `bolge=${bolge} yontem=parola`);
export const ETIKET = ham.map((k) => k[5]);

// Ayristirma: gunluk satiri metindir, alanlari duzenli ifadeyle cikarilir.
const DESEN = /^(\S+)T(\S+) (\S+) kimlik-dogrulama sonuc=(\w+) hesap=(\S+) bolge=(\S+) /;
export const ayristir = (satir) => {
  const m = DESEN.exec(satir);
  if (!m) return null;
  const [, , sa, makine, sonuc, hesap, bolge] = m;
  const [h, d, s] = sa.split(":").map(Number);
  return { t: h * 3600 + d * 60 + s, makine, sonuc, hesap, bolge };
};
export const OLAY = SATIR.map(ayristir);

if (import.meta.url === `file://${process.argv[1]}`) {
  console.log(`model (tohum ${TOHUM}): ${SATIR.length} gunluk satiri, ` +
    `${HESAP.length} personel ve ${SERVIS.length} servis hesabi (kurgu)`);
  for (const i of [0, 1]) console.log(SATIR[i]);
  const bozuk = OLAY.filter((o) => o === null).length;
  const bas = OLAY.filter((o) => o.sonuc === "basarisiz");
  console.log(`\nayristirilamayan satir ${bozuk}; basarisiz ${bas.length}, ` +
    `basarili ${OLAY.length - bas.length}`);
  const gen = (B) => (h) => h.map((v, j) => (j ? String(v).padStart(B[j])
    : String(v).padEnd(B[0]))).join("");
  const yz = gen([26, 12, 9, 10, 17]);
  console.log(yz(["kume (modelin dogrusu)", "basarisiz", "hesap", "bolge",
    "hesap basina en"]));
  for (const e of [...new Set(ETIKET)]) {
    const l = SATIR.map((_, i) => i).filter((i) => ETIKET[i] === e &&
      OLAY[i].sonuc === "basarisiz");
    const h = {};
    for (const i of l) h[OLAY[i].hesap] = (h[OLAY[i].hesap] || 0) + 1;
    console.log(yz([e, l.length, Object.keys(h).length,
      new Set(l.map((i) => OLAY[i].bolge)).size, Math.max(0, ...Object.values(h))]));
  }
}
model (tohum 20260314): 1168 gunluk satiri, 96 personel ve 14 servis hesabi (kurgu)
2026-03-14T00:10:00 uc-207 kimlik-dogrulama sonuc=basarisiz hesap=sv-204 bolge=toplayici-ag yontem=parola
2026-03-14T00:12:10 uc-207 kimlik-dogrulama sonuc=basarisiz hesap=sv-210 bolge=toplayici-ag yontem=parola

ayristirilamayan satir 0; basarisiz 916, basarili 252
kume (modelin dogrusu)       basarisiz    hesap     bolge  hesap basina en
eskimis-servis-kimligi             572        2         1              286
yazim-hatasi                        29       19         3                2
unutulmus-parola                    37        3         1               14
ayar-degisikligi                    62       62         1                1
puskurtme                          176       88         1                2
odakli-deneme                       40        1         1               40

Kümeler tablosu dersin bütün gerilimini tek ekranda veriyor. Günün 916 başarısız girişinin 572’si tek bir sorundan geliyor: kimliği eskimiş iki servis hesabı beş dakikada bir yeniden deniyor ve hesap başına 286 başarısızlık üretiyor. Bu sayı, günün en büyük kampanyasının on beş katıdır ve tamamen meşrudur.

Alt iki satırdaki kampanyaların biçimi birbirinin tersidir. Odaklı deneme tek hesapta 40 başarısızlık bırakıyor — derin ve dar. Püskürtme 88 hesaba yayılıyor ama hesap başına yalnız iki deneme yapıyor — sığ ve geniş. Dördüncü satır ikinci biçimi ayırmanın neden zor olduğunu söylüyor: sunucu tarafı bir ayar değişikliği 62 hesapta birer başarısızlık üretti ve şekli püskürtmeye benziyor.

Hesap Başına Eşik

// esik.mjs — esik secimi: kacirilan olay, gereksiz uyari ve kilitlemenin durdurdugu mesru is.
import { OLAY, ETIKET, SATIR } from "./giris.mjs";

const KAMPANYA = ["odakli-deneme", "puskurtme"];
const bas = [];
OLAY.forEach((o, i) => { if (o.sonuc === "basarisiz")
  bas.push({ ...o, etiket: ETIKET[i], id: bas.length }); });
const basarili = OLAY.map((o, i) => ({ ...o, etiket: ETIKET[i] }))
  .filter((o) => o.sonuc === "basarili");
const kampanyaOlay = bas.filter((o) => KAMPANYA.includes(o.etiket));

// Kayan pencerede bir anahtarin (hesap ya da bolge) esigi ilk gectigi an ve o penceredeki olaylar.
function gecis(anahtar, olcu, esik, pencere) {
  const ilk = new Map();
  for (const [i, o] of bas.entries()) {
    const k = anahtar(o);
    if (ilk.has(k)) continue;
    const p = bas.slice(0, i + 1).filter((x) => anahtar(x) === k && x.t > o.t - pencere);
    if (olcu(p) >= esik) ilk.set(k, { t: o.t, p });
  }
  return ilk;
}
const sayi = (p) => p.length;
const ayriHesap = (p) => new Set(p.map((x) => x.hesap)).size;

// Degerlendirme uyarinin PENCERESINE bakar: kampanya olayi iceriyor mu.
function degerlendir(uyari) {
  const kapsanan = new Set();
  let bos = 0;
  for (const [, v] of uyari) {
    const k = v.p.filter((o) => KAMPANYA.includes(o.etiket));
    if (k.length === 0) bos++;
    for (const o of k) kapsanan.add(o.id);
  }
  const yakalanan = new Set(kampanyaOlay.filter((o) => kapsanan.has(o.id))
    .map((o) => o.etiket));
  return { yakalanan: yakalanan.size, kacan: kampanyaOlay.length - kapsanan.size, bos };
}

const gen = (B) => (h) => h.map((v, j) => (j ? String(v).padStart(B[j])
  : String(v).padEnd(B[0]))).join("");
const y1 = gen([10, 7, 12, 12, 12, 11, 19]);
const y2 = gen([7, 8, 12, 12, 11, 19]);

console.log(`${SATIR.length} satir, ${bas.length} basarisiz giris; iki kampanya ` +
  `(${KAMPANYA.join(", ")}) toplam ${kampanyaOlay.length} olay uretti`);
console.log("\nkural 1 — hesap basina basarisizlik sayisi");
console.log(y1(["pencere", "esik", "kilitlenen", "yakalanan", "kacan olay", "gereksiz",
  "durdurulan giris"]));
for (const [ad, pencere] of [["1 saat", 3600], ["24 saat", 86400]])
  for (const esik of [3, 5, 10, 20]) {
    const u = gecis((o) => o.hesap, sayi, esik, pencere);
    const d = degerlendir(u);
    const durdurulan = [...u].reduce((a, [k, v]) => a + basarili
      .filter((b) => b.hesap === k && b.t >= v.t && b.etiket !== "puskurtme").length, 0);
    console.log(y1([ad, esik, u.size, `${d.yakalanan}/2`, d.kacan, d.bos, durdurulan]));
  }

console.log("\nkural 2 — bolge basina AYRI hesap sayisi (pencere 1 saat)");
console.log(y2(["esik", "uyari", "yakalanan", "kacan olay", "gereksiz", "engellenen hesap"]));
for (const esik of [10, 20, 40, 70, 90]) {
  const u = gecis((o) => o.bolge, ayriHesap, esik, 3600);
  const d = degerlendir(u);
  const engel = new Set([...u].filter(([, v]) => !v.p.some((o) =>
    KAMPANYA.includes(o.etiket))).flatMap(([, v]) => v.p.map((o) => o.hesap))).size;
  console.log(y2([esik, u.size, `${d.yakalanan}/2`, d.kacan, d.bos, engel]));
}

const enBuyuk = Math.max(...bas.map((o, i) => new Set(bas.slice(0, i + 1)
  .filter((x) => x.bolge === o.bolge && x.t > o.t - 3600 && !KAMPANYA.includes(x.etiket))
  .map((x) => x.hesap)).size));
const p = bas.filter((o) => o.etiket === "puskurtme");
const hesapBasi = [...new Set(p.map((o) => o.hesap))]
  .map((h) => p.filter((o) => o.hesap === h).length);
console.log(`\npuskurtme: ${new Set(p.map((o) => o.hesap)).size} hesap, hesap basina en cok ` +
  `${Math.max(...hesapBasi)} deneme, 1 basarili giris`);
console.log(`en buyuk MESRU toplu basarisizlik: bir saatte ${enBuyuk} ayri hesap`);
1168 satir, 916 basarisiz giris; iki kampanya (odakli-deneme, puskurtme) toplam 216 olay uretti

kural 1 — hesap basina basarisizlik sayisi
pencere      esik  kilitlenen   yakalanan  kacan olay   gereksiz   durdurulan giris
1 saat          3           6         1/2         213          5                  9
1 saat          5           6         1/2         211          5                  9
1 saat         10           6         1/2         206          5                  9
1 saat         20           0         0/2         216          0                  0
24 saat         3          70         2/2         104         11                 49
24 saat         5          12         2/2         199          5                 16
24 saat        10           6         1/2         206          5                  9
24 saat        20           3         1/2         196          2                  0

kural 2 — bolge basina AYRI hesap sayisi (pencere 1 saat)
esik      uyari   yakalanan  kacan olay   gereksiz   engellenen hesap
10            2         1/2         206          1                 10
20            2         1/2         196          1                 20
40            2         1/2         176          1                 40
70            1         1/2         146          0                  0
90            0         0/2         216          0                  0

puskurtme: 88 hesap, hesap basina en cok 2 deneme, 1 basarili giris
en buyuk MESRU toplu basarisizlik: bir saatte 62 ayri hesap

Birinci tablonun ilk üç satırı üç ayrı eşiği deniyor ve üçü de aynı sonucu veriyor: altı hesap kilitleniyor, iki kampanyanın biri yakalanıyor, 216 kampanya olayının 206 ile 213 arası kaçıyor. Üçe, beşe ve ona ayarlanmış eşikler arasında ölçülebilir bir tespit farkı yoktur; üçü de aynı beş meşru hesabı yakalar, çünkü bir saatlik pencerede on başarısızlığı geçen tek şeyler eskimiş servis kimlikleri, parolasını unutan kullanıcılar ve odaklı denemedir.

Tablodaki gereksiz sütunu penceresinde kampanya olayı bulunmayan uyarıyı, yani yanlış pozitifi sayar: her eşikte beş uyarı meşru bir nedenden geliyor ve kilitleme açıksa dokuz meşru giriş duruyor. İkisi servis hesabıdır; kilitlendiklerinde duran şey bir kullanıcı değil, sayaç toplama işidir. Eşiği yirmiye çekmek yanlış pozitifle birlikte tespiti de sıfırlıyor: yakalanan kampanya sıfır, kaçan olay 216.

Pencereyi yirmi dört saate açmak tabloyu değiştiriyor ama sorunu çözmüyor. Üç eşiğinde her iki kampanya da yakalanıyor ve kaçan olay 104’e iniyor; bedeli 70 kilitlenen hesap, 11 yanlış pozitif ve 49 durdurulmuş meşru giriştir. Bu, gün içinde bir kez parolasını yanlış yazan herkesin akşama kadar sisteme girememesi demektir. Duyarlılığı pencereden almanın faturası budur.

Yakalamanın nasıl olduğu da önemlidir: püskürtme, hesap başına iki denemesi gün içindeki meşru bir başarısızlıkla toplandığı için görünüyor. Kural onu püskürtme olarak değil, üç başarısızlık biriktirmiş bir hesap olarak görüyor ve hiç meşru başarısızlığı olmayan hesaplarda hâlâ görmüyor.

Aynı Olayı Bölge Ekseninde Saymak

Hesap başına sayan bir kural püskürtmeyi hiçbir eşikte tek başına göremez, çünkü ölçtüğü büyüklük yanlıştır: kampanya hesap başına iki denemede kalıyor ve iki, meşru yazım hatası düzeyinin altındadır. Eşiği düşürmek burada yardım etmez, yalnız yazım hatalarını uyarıya çevirir. Değişmesi gereken şey eşik değil, sayılan anahtardır.

İkinci tablo aynı günlüğü bölge başına ayrı hesap sayarak okuyor. On, yirmi ve kırk eşiklerinde iki uyarı çıkıyor ve biri yanlış pozitiftir: sunucu tarafı ayar değişikliği 62 şube hesabında birer başarısızlık üretmişti ve bu kural onu bir kampanya gibi görüyor. Bölge engellemeye bağlanmış bir kuralda bedel doğrudan okunuyor — kırk eşiğinde 40 meşru hesap engellenir.

Yetmiş eşiğinde uyarı tek kalıyor, yanlış pozitif sıfırlanıyor ve püskürtme ayrılıyor. Bu satır umut verici görünür, ama son çıktı satırı sınırı yazıyor: en büyük meşru toplu başarısızlık bir saatte 62 hesaptır. Kural yalnız bundan geniş yayılan denemeleri yanlış pozitif üretmeden ayırabilir. Aynı kampanya 50 hesaba yayılsaydı hiçbir eşikte ayrılamayacaktı; doksan eşiğinde ise bu kampanya da kaçıyor ve 216 olayın tamamı görünmez oluyor.

Kursun ölçüsüne çevrildiğinde tablo şunu söylüyor: kimlik doğrulama günlüğü hiçbir tutunma noktasını kapatmıyor, yalnız noktaların kurulmasından önceki adımı görünür kılıyor ve o görünürlük eşiğe bağlı. Püskürtmenin ürettiği tek başarılı giriş de kayıtta duruyor, ama başarısızlık eşiği başarılı girişlere hiç bakmaz.

Özet

  • Günün 916 başarısız girişinin 572’si tek bir meşru sorundan geliyor: kimliği eskimiş iki servis hesabı, hesap başına 286 başarısızlıkla en büyük kampanyanın on beş katını üretiyor.
  • Hesap başına sayan kural bir saatlik pencerede hangi eşikte olursa olsun aynı altı hesabı kilitliyor; 216 kampanya olayının 206’sı kaçıyor, 5 uyarı yanlış pozitif ve 9 meşru giriş duruyor.
  • Pencereyi 24 saate açmak iki kampanyayı da yakalıyor ve kaçan olayı 104’e indiriyor; bedeli 70 kilitlenen hesap, 11 yanlış pozitif ve 49 durdurulmuş meşru giriştir.
  • Püskürtme hesap başına en çok 2 deneme yaptığı için hesap eksenli hiçbir eşikte görünmez; iki sayısı meşru yazım hatası düzeyinin altındadır ve eşiği düşürmek yalnız yazım hatalarını uyarıya çevirir.
  • Bölge başına ayrı hesap sayan kural 70 eşiğinde püskürtmeyi yanlış pozitif üretmeden ayırıyor; bunun tabanı meşru toplu başarısızlığın büyüklüğüdür — bir saatte 62 hesap.

Sonraki Adım

Her iki kural da tek bir alana bakıyordu: giriş başarısız mı, hangi hesapta, hangi bölgede. Oturum açıldıktan sonra ne olduğu bu günlükte yoktur; püskürtmenin ürettiği başarılı giriş, öteki 251 başarılı girişten ayırt edilemez. Bir sonraki ders o oturumun içine bakar ve ilk dersin tablosunda sekiz türü tek başına adıyla yazan kaynağı açar: süreç oluşturma kayıtları. Ölçü orada üst süreç bağlamıdır — aynı komut listesi düz bir dizi olarak okunduğunda kaç kalem şüpheli görünüyor, ağaç olarak okunduğunda kaçı ayrılıyor ve kaydın hacmi ne.

İlerlemeni kaydetmek ve not almak için Giriş yap

Notlarım

Not almak için giriş yapmalısın.

Aramak için yazmaya başlayın.

↑↓ Esc gezin · aç · kapat