Ders 04 / 12
Depo Geçmişinde Sır Tarama
940 dizi sabitinde dört desenin birlikte çalışması: entropi eşiği 0,60'tan kapalıya çekildiğinde eşleşme 855'ten 519'a inerken yanlış pozitif oranı 68,0'dan ancak 52,8'e düşer, çünkü gürültünün kaynağı entropi değil 442 eşleşmenin 270'ini yanlış çıkaran anahtar sözcük desenidir; 310 sırrın 50'si hiçbir desene takılmaz ve 26'sı tek bir sınıftadır. Üç yerleşim aynı desen kümesini taşır: her yapıda çalışma ağacı 1 057 dakika tarayıp 18 sırra hiç bakmaz, artımlı fark 9 dakikaya iner ama geriye kalan 164 sırrı hiç görmez, bir kerelik tam tarihçe 48 dakikada geçmişin tamamını okur ve 14 sırrın yalnız orada durduğunu gösterir.
İçindekiler
Bir erişim anahtarı bir yapılandırma satırına elle yazıldığında derleme geçer, sınamalar geçer ve önceki üç denetim de temiz döner: değer geçerli bir dizedir, çalışan uçta hata üretmez, bir bağımlılık kaydına karşılık gelmez. Onu görecek denetim dosyaların içindeki dizi sabitlerine bakar.
Sır tarama (secret scanning), depo içeriğindeki dizi sabitlerini bir desen kümesinden geçirip gizli olma ihtimali taşıyanları çıkaran denetimdir. Güvenli Kodlama kursunda aynı depo geçmişi bir kez ölçülmüştü, ama ölçülen şey sırrın maruziyetiydi: bir değerin kaç işlem boyunca açık kaldığı, silmenin neyi kapatmadığı. Burada ölçülen şey denetimin kendisidir — hangi desen kaç bulgu üretiyor, gürültü hangisinden geliyor, hangi sır sınıfı hiçbir desene takılmıyor ve bütün bunlar hattan kaç dakika alıyor.
- OD19. Depo geçmişi üç deponun ortak 1 800 işlemesi ve 940 dizi sabitidir; kurgudur ve hiçbir gerçek sır biçimi yazılmaz. Bir dizi sabiti bir dosyaya yazılmış değişmez metin değeridir; gerçekten gizli olup olmadığı modelin doğrusudur, tarayıcı yalnız biçime bakar.
- OD20. Desen kümesi dörttür. Önek biçimi ve blok başlığı yalnız biçimi belli sınıfları yakalar. Anahtar sözcük ataması değere değil, değerin atandığı ada bakar. Entropi eşiği eşiğin üstünde kalan her diziyi alır ve ayarlanabilen tek desendir.
- OD21. Entropi, dizinin karakter dağılımının düzensizliğini 0 ile 1 arasında veren model ölçüsüdür; rastgele değerler yukarıda, sözcükler aşağıda durur.
- OD22. Bir dizinin çalışma ağacından çıkarılması onu geçmişten çıkarmaz ve döndürme değildir; bu, Güvenli Kodlama kursunda ölçülmüştü, burada girdi olarak alınır.
- OD23. Tarayıcı 900. işlemede kurulur, ondan önce hiç koşmamıştır; yapılar on işlemede bir alınır, toplam 90 yapı. Taranan kalem başına 0,02, incelenen yanlış pozitif başına 4 model dakikası harcanır. Süreler veridir, ölçüm değildir.
Gürültüyü Hangi Desen Üretiyor
// sir.mjs — depo gecmisindeki dizi sabitleri desen kumesinden geciriliyor; olculen sey // eslesme, gercek sir, yanlis pozitif ve hicbir desenin gormedigi kalemdir. MODELDIR. export const TOHUM = 20260329, ISLEME = 1800, DIZI = 940, KALEM_DK = 0.02; const uretec = (t) => { let s = t >>> 0; return () => (s = (s * 1664525 + 1013904223) >>> 0) / 4294967296; }; const r = uretec(TOHUM); // [ad, pay, sir olasiligi, entropi tabani, entropi tavani, ada atanma olasiligi, bicim] // sir = o sinifin gercekten gizli olma olasiligi; bicim = onek/blok deseninin tanidigi kalip. export const SINIF = [ ["onekli erisim anahtari", 0.09, 0.93, 0.70, 0.96, 0.55, "onek"], ["rastgele oturum sirri", 0.11, 0.82, 0.66, 0.94, 0.72, ""], ["ozel anahtar blogu", 0.04, 0.96, 0.55, 0.80, 0.10, "blok"], ["baglanti dizesi", 0.10, 0.68, 0.34, 0.72, 0.86, ""], ["sozcuk parola", 0.08, 0.62, 0.16, 0.40, 0.34, ""], ["ozet degeri", 0.17, 0.00, 0.74, 0.95, 0.12, ""], ["sinama yer tutucusu", 0.23, 0.03, 0.28, 0.82, 0.78, ""], ["tekil kimlik", 0.18, 0.00, 0.58, 0.86, 0.18, ""], ].map(([ad, pay, sir, e0, e1, ata, bicim]) => ({ ad, pay, sir, e0, e1, ata, bicim })); const sinifSec = (u) => { let t = 0; for (const s of SINIF) { t += s.pay; if (u < t) return s; } return SINIF.at(-1); }; // Her dizi bir islemede girer, bir bolumu sonraki bir islemede calisma agacindan // cikarilir. Cikarilmak sirri gecersiz kilmaz; tarihcede oldugu yerde durur. export const DIZILER = Array.from({ length: DIZI }, (_, i) => { const s = sinifSec(r()); const giris = Math.floor(r() * ISLEME), ent = s.e0 + r() * (s.e1 - s.e0); const silindi = r() < 0.30 ? giris + 1 + Math.floor(r() * (ISLEME - giris)) : null; return { i, sinif: s, sir: r() < s.sir, ent, ata: r() < s.ata, giris, silindi, rev: 1 + Math.floor(r() * 9) }; }); export const desenler = (esik) => [ { ad: "onek bicimi", tut: (d) => d.sinif.bicim === "onek" }, { ad: "blok basligi", tut: (d) => d.sinif.bicim === "blok" }, { ad: "anahtar sozcuk atamasi", tut: (d) => d.ata }, { ad: "entropi esigi", tut: (d) => d.ent >= esik }, ]; export const eslerMi = (d, esik) => desenler(esik).some((p) => p.tut(d)); const gen = (B) => (h) => h.map((v, j) => (j ? String(v).padStart(B[j]) : String(v).padEnd(B[0]))).join(""); if (import.meta.url === `file://${process.argv[1]}`) { const sirlar = DIZILER.filter((d) => d.sir); console.log(`model (tohum ${TOHUM}): ${ISLEME} isleme, ${DIZI} dizi sabiti, ` + `${sirlar.length} tanesi gercekten sir; ${DIZILER.filter((d) => d.silindi).length} dizi ` + `calisma agacindan cikarilmis`); const y1 = gen([16, 10, 9, 9, 12, 12]); console.log("\nentropi esigi degisiyor, oteki uc desen sabit"); console.log(y1(["entropi esigi", "eslesme", "gercek", "yanlis+", "yanlis+ %", "gorulmeyen"])); for (const t of [0.60, 0.80, 1.01]) { const e = DIZILER.filter((d) => eslerMi(d, t)), g = e.filter((d) => d.sir).length; console.log(y1([t > 1 ? "kapali" : t.toFixed(2), e.length, g, e.length - g, (100 * (e.length - g) / e.length).toFixed(1), sirlar.length - g])); } const ESIK = 0.80, ds = desenler(ESIK); const y2 = gen([24, 10, 9, 9, 12]); console.log(`\nesik ${ESIK.toFixed(2)}'de desen basina katki`); console.log(y2(["desen", "eslesme", "gercek", "yanlis+", "tek kaynak"])); for (const p of ds) { const l = DIZILER.filter((d) => p.tut(d)); const tek = l.filter((d) => ds.filter((q) => q.tut(d)).length === 1 && d.sir).length; console.log(y2([p.ad, l.length, l.filter((d) => d.sir).length, l.filter((d) => !d.sir).length, tek])); } const y3 = gen([24, 7, 12, 13, 13]); console.log(`\nesik ${ESIK.toFixed(2)}'de sinifa gore gorulmeyen sir`); console.log(y3(["dizi sinifi", "dizi", "gercek sir", "eslesen sir", "gorulmeyen"])); for (const s of SINIF) { const l = DIZILER.filter((d) => d.sinif === s), sl = l.filter((d) => d.sir); const e = sl.filter((d) => eslerMi(d, ESIK)).length; console.log(y3([s.ad, l.length, sl.length, e, sl.length - e])); } }
model (tohum 20260329): 1800 isleme, 940 dizi sabiti, 310 tanesi gercekten sir; 269 dizi calisma agacindan cikarilmis entropi esigi degisiyor, oteki uc desen sabit entropi esigi eslesme gercek yanlis+ yanlis+ % gorulmeyen 0.60 855 274 581 68.0 36 0.80 677 260 417 61.6 50 kapali 519 245 274 52.8 65 esik 0.80'de desen basina katki desen eslesme gercek yanlis+ tek kaynak onek bicimi 93 89 4 12 blok basligi 39 37 2 32 anahtar sozcuk atamasi 442 172 270 86 entropi esigi 281 105 176 15 esik 0.80'de sinifa gore gorulmeyen sir dizi sinifi dizi gercek sir eslesen sir gorulmeyen onekli erisim anahtari 93 89 89 0 rastgele oturum sirri 102 83 71 12 ozel anahtar blogu 39 37 37 0 baglanti dizesi 89 56 44 12 sozcuk parola 66 39 13 26 ozet degeri 179 0 0 0 sinama yer tutucusu 214 6 6 0 tekil kimlik 158 0 0 0
İlk tablo ayarlanabilir tek düğmeyi sonuna kadar çeviriyor. Entropi eşiği 0,60’ta eşleşme 855 ve yanlış pozitif oranı yüzde 68,0; desen tamamen kapatıldığında eşleşme 519’a iniyor ama oran ancak yüzde 52,8’e düşüyor. Gürültünün üçte ikisi eşiğin dokunmadığı yerdedir. Kapatmanın bedeli de aynı satırda: gerçek bulgu 274’ten 245’e iniyor, görülmeyen sır 36’dan 65’e çıkıyor.
İkinci tablo kaynağı adıyla yazıyor. Anahtar sözcük ataması deseni tek başına 442 eşleşme üretiyor ve 270’i yanlış pozitif — eşik 0,80’deki bütün gürültünün üçte ikisi. Nedeni desenin ne yaptığındadır: değere değil, değerin atandığı ada bakar; adı bir parola alanına benzeyen her satır eşleşir, içindeki değer bir sınama yer tutucusu olsa da. Önek biçimi deseni 93 eşleşmede 4, blok başlığı 39 eşleşmede 2 yanlış pozitif veriyor. Bir desen kümesinin yanlış pozitif oranı ortalama bir değer değildir; neredeyse tamamı tek bir desenden gelir ve o desen kaldırılmadan oran düşmez.
Son sütun kaldırma kararını zorlaştırıyor. Aynı desen 86 gerçek sırrın tek kaynağıdır; blok başlığı 32, entropi eşiği 15, önek biçimi 12 kalemde tek kaynaktır. En gürültülü desen en çok tekil katkıyı veren desendir, bu yüzden karar kaldırmak değil onun bulgularını ayrı bir kuyruğa almaktır: 270 yanlış pozitif aynı listeye girdiğinde 86 tekil gerçek bulgu arasında kaybolur.
Üçüncü tablo eşikten bağımsız kör noktayı veriyor. Sözcük parola sınıfının 39 gerçek sırrının 26’sı hiçbir desene takılmıyor: entropisi düşüktür, öneki yoktur ve üçte ikisi bir parola adına atanmamıştır. Bağlantı dizesi ve rastgele oturum sırrı sınıfları da on ikişer kalem kaçırıyor; toplam 50 sır taranmış olduğu hâlde görülmüyor. Karşıt uç da tabloda: özet değeri ve tekil kimlik sınıflarında 337 dizi var ve içlerinde tek bir sır yok — ikisi de entropi ölçüsünde yukarıda durduğu için eşik düşürüldükçe raporu bunlar doldurur.
Tarihçenin Bedeli ve Artımlının Kör Noktası
// tarihce.mjs — ayni desen kumesi uc yerlesimde kosuyor: her yapida calisma agaci, // her yapida artimli fark ve bir kereye mahsus tam tarihce. Sureler MODEL dakikasidir. import { DIZILER, ISLEME, KALEM_DK, eslerMi } from "./sir.mjs"; const ESIK = 0.80, YAPI = 90, BASLANGIC = 900, INCELEME_DK = 4; const komut = (y) => BASLANGIC + Math.round((y + 1) * (ISLEME - BASLANGIC) / YAPI); const canli = (d, c) => d.giris <= c && (d.silindi === null || d.silindi > c); const SIR = DIZILER.filter((d) => d.sir); const KOMUTLAR = Array.from({ length: YAPI }, (_, y) => komut(y)); // Yalniz tarihcede duran dizi: hicbir yapi aninda calisma agacinda degil. const yalnizTarihce = (d) => !KOMUTLAR.some((c) => canli(d, c)); // Bir yerlesim, her yapida hangi kalem kumesinin tarandigini soyler. Calisma agaci // yerlesimi o andaki dosyalari, artimli yerlesim yalniz onceki yapidan beri gireni // gorur; tam tarihce kurulus aninda gecmisteki her revizyonu bir kez okur. const GECMIS = DIZILER.filter((d) => d.giris <= BASLANGIC); function olc(ad, kume, birKerelik = 0) { const gorulen = new Set(), blokeYapi = new Set(), bakilan = new Set(); let taranan = birKerelik; if (birKerelik) for (const d of GECMIS) { bakilan.add(d); if (eslerMi(d, ESIK)) gorulen.add(d); } for (let y = 0; y < YAPI; y++) { const liste = kume(komut(y), y ? komut(y - 1) : BASLANGIC); taranan += liste.length; for (const d of liste) { bakilan.add(d); if (gorulen.has(d) || !eslerMi(d, ESIK)) continue; gorulen.add(d); blokeYapi.add(y); } } const gercek = [...gorulen].filter((d) => d.sir); const yanlis = gorulen.size - gercek.length; return { ad, taranan, eslesme: gorulen.size, gercek: gercek.length, yanlis, bakilmadi: SIR.filter((d) => !bakilan.has(d)).length, kacan: SIR.filter((d) => bakilan.has(d) && !gorulen.has(d)).length, bloke: blokeYapi.size, dk: Math.round(taranan * KALEM_DK), incDk: yanlis * INCELEME_DK, silinmis: gercek.filter(yalnizTarihce).length }; } const REVIZYON = GECMIS.reduce((a, d) => a + d.rev, 0); const YERLESIM = [ olc("her yapida calisma agaci", (c) => DIZILER.filter((d) => canli(d, c))), olc("her yapida artimli fark", (c, o) => DIZILER.filter((d) => d.giris > o && d.giris <= c)), olc("tam tarihce + artimli", (c, o) => DIZILER.filter((d) => d.giris > o && d.giris <= c), REVIZYON), ]; const gen = (B) => (h) => h.map((v, j) => (j ? String(v).padStart(B[j]) : String(v).padEnd(B[0]))).join(""); const y = gen([26, 9, 8, 9, 11, 13, 8, 11, 9]); console.log(`${YAPI} yapi, ${BASLANGIC}. islemede kurulan tarayici, ${SIR.length} gercek sir; ` + `tam tarihce ${REVIZYON} dizi revizyonu okur, kalem basina ${KALEM_DK} model dakikasi`); console.log(y(["yerlesim", "eslesme", "gercek", "yanlis+", "bakilmadi", "desen kacan", "bloke", "tarama dk", "inc. dk"])); for (const o of YERLESIM) { console.log(y([o.ad, o.eslesme, o.gercek, o.yanlis, o.bakilmadi, o.kacan, o.bloke, o.dk, o.incDk])); } const tam = YERLESIM.at(-1); console.log(`\ntam tarihce bir kez ${Math.round(REVIZYON * KALEM_DK)} dakika alip ` + `${tam.gercek} sirri buluyor; ${tam.silinmis} tanesi hicbir yapi aninda calisma agacinda ` + `degil, silinmis ama dondurulmedigi surece gecerli`); console.log(`desen korlugu yerlesimden bagimsizdir: tam tarihcede ${tam.kacan} sir okundugu ` + `halde hicbir desene takilmiyor. Pahali olan tarama da degil inceleme: ${tam.dk} dakika ` + `tarama karsiliginda ${tam.incDk} dakika, cunku ${tam.eslesme} eslesmenin ${tam.yanlis} ` + `tanesi yanlis pozitiftir`);
90 yapi, 900. islemede kurulan tarayici, 310 gercek sir; tam tarihce 2378 dizi revizyonu okur, kalem basina 0.02 model dakikasi yerlesim eslesme gercek yanlis+ bakilmadi desen kacan bloke tarama dk inc. dk her yapida calisma agaci 640 246 394 18 46 89 1057 1576 her yapida artimli fark 341 127 214 164 19 89 9 856 tam tarihce + artimli 677 260 417 0 50 89 57 1668 tam tarihce bir kez 48 dakika alip 260 sirri buluyor; 14 tanesi hicbir yapi aninda calisma agacinda degil, silinmis ama dondurulmedigi surece gecerli desen korlugu yerlesimden bagimsizdir: tam tarihcede 50 sir okundugu halde hicbir desene takilmiyor. Pahali olan tarama da degil inceleme: 57 dakika tarama karsiliginda 1668 dakika, cunku 677 eslesmenin 417 tanesi yanlis pozitiftir
Üç satır aynı dört deseni taşıyor; ayrıldıkları yer neye baktıklarıdır. En yaygın kurulum ikinci satırdır: her yapıda yalnız o yapının getirdiği farkı taramak. 9 dakika harcıyor ve 127 sır buluyor. Aynı satırda 164 sırrın hiç bakılmadığı yazılı — tarayıcı kurulmadan önce depoya girmiş kalemler. Artımlı bir denetim onlara asla uğramaz ve her koşumda temiz rapor verir, çünkü baktığı küme her zaman yenidir. Bir artımlı taramanın kapsama listesi kurulduğu işlemedir; o tarih raporda yazılı değilse sıfır bulgu ile hiç bakılmamış olmak ayırt edilemez.
Birinci satır bu boşluğu pahalı kapatıyor. Her yapıda çalışma ağacının tamamını taramak 1 057 dakika harcıyor — artımlı yerleşimin yüz on yedi katı. Karşılığında kurulmadan önce girmiş ve hâlâ duran sırları görüyor: hiç bakılmayan sayısı 164’ten 18’e iniyor. Kalan 18 kalem hiçbir yapı anında çalışma ağacında değildir. Bloke sütunu üç yerleşimi ayırmıyor: üçü de 90 yapının 89’unu en az bir kez durduruyor, çünkü bloklayan şey gerçek sır değil, kuyruğa düşen her yeni eşleşmedir.
Üçüncü satır sıralamayı tersine çeviriyor. Kuruluş anında geçmişin tamamını taramak bir kerelik 2 378 dizi revizyonu okur ve 48 dakika sürer; çalışma ağacı yerleşiminin dört yapıda harcadığından azdır. Karşılığında hiç bakılmayan sır sıfıra iner, gerçek bulgu 260’a çıkar ve bunların 14’ü hiçbir yapı anında çalışma ağacında değildir — silinmiş, ama silme döndürme olmadığı için hâlâ geçerli. Bu 14 kalem yalnız bu yerleşimde görünür. Tarihçeyi taramak pahalı bir iş değildir; pahalı olan onu her yapıda yeniden taramaktır.
Son iki sütun bedelin yerini yazıyor. Tam tarihçe yerleşiminde 57 dakika tarama karşılığında 1 668 dakika inceleme çıkıyor: bedelin yüzde 97’si 417 yanlış pozitifin açılıp kapatılmasıdır. Bir sır taramasının hattan aldığı sürenin ölçüsü koşum süresi değil, yanlış pozitif oranıdır, ve o oranın nereden geldiği bir önceki bölümde yazılıydı.
Özet
- Ayarlanabilir tek desen olan entropi eşiği yanlış pozitif oranını yüzde 68,0’dan ancak 52,8’e indirir ve bu sırada gerçek bulgu 274’ten 245’e düşer.
- Gürültünün kaynağı tek bir desendir: anahtar sözcük ataması 442 eşleşmenin 270’ini yanlış çıkarır, çünkü değere değil değerin atandığı ada bakar. Aynı desen 86 gerçek sırrın tek kaynağıdır, bu yüzden karar kaldırmak değil ayrı bir kuyruğa almaktır.
- 310 sırrın 50’si taranmış olduğu hâlde hiçbir desene takılmaz; 26’sı tek bir sınıftadır — düşük entropili, öneksiz ve bir parola adına atanmamış sözcük parolalar.
- Üç yerleşim üç ayrı kör nokta taşır: artımlı fark 9 dakikada koşar ama kurulmadan önceki 164 sırrı hiç görmez, her yapıda çalışma ağacı 1 057 dakika harcar ve 18’ini görmez, bir kerelik tam tarihçe 48 dakikada geçmişin tamamını okur ve yalnız orada duran 14 sırrı ortaya çıkarır.
- Bedelin yüzde 97’si tarama değil incelemedir: 57 dakika koşum karşılığında 417 yanlış pozitif için 1 668 dakika harcanır.
Sonraki Adım
Dört denetim de aynı yerde durdu: depodaki dosyalar. Oysa üretime giden şey dosya değil bir imajdır — derlenmiş çıktı, gereken kitaplıklar ve altlarındaki işletim katmanı tek bir yapıda birleşir. Bu yapının açıkları iki ayrı yerden gelir ve düzeltme yolları benzemez: bir bölümü ekibin eklediği katmanlardadır, bir bölümü hiç dokunulmamış temel katmandan miras alınır. İkincisi için yazılacak tek satır kod yoktur; kapatan şey bir yükseltmedir. Sonraki ders bir imaj katman listesinde bu iki kaynağı ayırır ve temel katmanı yükseltmenin açıkların kaçını kapattığını sayar.
İlerlemeni kaydetmek ve not almak için Giriş yap
Notlarım
Not almak için giriş yapmalısın.