İçeriğe geç
academia.sh

Ders 15 / 17

Kodda Gömülü Sırlar

Kurgu bir depo geçmişinde sırrın açık kaldığı işlem sayısı ve desen taramasının kapsaması: beş sırrın çalışma ağacında 124, geçmişte 223 işlem görünmesi, tarihçe temizlemenin on dokuz kopyanın on sekizine erişememesi, anlık görüntü taramasının beş sırdan yalnız birini görmesi ve aynı kuralın geçmişte 76,8 kat bulgu ile 0,69 yanlış alarm oranı üretmesi.

İçindekiler

Önceki iki ders anahtarın ve belirtecin nasıl üretildiğini ölçtü ve ikisi de aynı varsayıma dayandı: üretilen değerin yalnız onu üreten süreçte kaldığına. Bu varsayım bir bölüm değer için hiç doğru olmaz. O değerler üretilmemiştir; bir yapılandırma satırına elle yazılmış, oradan da sürüm denetimine girmiştir. Girdikleri anda bir dosyada değil, bir geçmişte dururlar ve geçmişin kendine özgü bir ölçüsü vardır.

Gizli Değer Yönetimi dersi üretimdeki değerin döndürme penceresini ve sızdığında ne kadar süre geçerli kaldığını ölçmüştü. Burada ölçülen şey saklama pratiği değil, kapsamadır: kaç işlemde sır kalmış, silmek kaç işlemi kapatıyor, bir tarama kuralı kaç noktayı görüyor ve görmek için kaç yanlış alarm ödeniyor. Aşağıdaki depo geçmişi bir modeldir; işlem sayıları, dosya adları ve değerler kurgudur ve hiçbiri gerçek bir sır biçimi taşımaz.

Depo Geçmişinde Bir Sır

KI7 — bir değer işlendiği anda depo geçmişine girer; çalışma ağacından silinmesi geçmişten silinmesi değildir. Silme yeni bir işlemdir ve eski işlemler yerinde durur. Bir sırrın gerçekten kapandığı an, değerin geçersiz kılındığı — döndürüldüğü — andır.

// depo/gecmis.mjs — kurgu bir depo gecmisi (model): 60 islem, bes kurgu sir. Sir degerleri
// asagida kendi uretecimizle uretilir; gercek bir sir bicimi, gercek anahtar deseni ve
// gercek servis adi kullanilmaz. giren: degerin islendigi islem; silinen: calisma agacindan
// cikarildigi islem; dondurulen: degerin gecersiz kilindigi islem (null = hic).
export const ISLEM = 60;
let durum = 4703;
export const rast = () => (durum = (durum * 1103515245 + 12345) % 2 ** 31) / 2 ** 31;
const ABC = 'abcdefghijkmnpqrstuvwxyzACDEFGHJKLMNPQRTUVWXYZ2346789';
export const uret = (n) => Array.from({ length: n }, () => ABC[Math.floor(rast() * ABC.length)]).join('');

export const sirlar = [
  { ad: 'saha imza anahtari', giren: 7, silinen: 19, dondurulen: null },
  { ad: 'rapor aktarim parolasi', giren: 12, silinen: null, dondurulen: null },
  { ad: 'portal oturum tuzu', giren: 3, silinen: 41, dondurulen: 44 },
  { ad: 'alim ust anahtari', giren: 22, silinen: 26, dondurulen: null },
  { ad: 'is emri geri cagirma anahtari', giren: 33, silinen: 55, dondurulen: 51 },
];

const yaz = (g, ...s) => console.log(s.map((v, i) =>
  (g[i] < 0 ? String(v).padEnd(-g[i]) : String(v).padStart(g[i]))).join(''));
const yok = (x) => (x === null ? '-' : x);

// KI7: bir sir islendigi anda gecmise girer; calisma agacindan silinmesi gecmisten
// silinmesi degildir. Kapanma yalnizca dondurme ile olur.
const D = [-30, 8, 9, 12, 9, 10, 8];
yaz(D, 'sir', 'giren', 'silinen', 'dondurulen', 'agacta', 'gecmiste', 'acik');
let agacta = 0, gecmiste = 0, acik = 0;
for (const s of sirlar) {
  const a = (s.silinen ?? ISLEM) - s.giren;
  const g = ISLEM - s.giren;
  const c = (s.dondurulen ?? ISLEM) - s.giren;
  agacta += a; gecmiste += g; acik += c;
  yaz(D, s.ad, s.giren, yok(s.silinen), yok(s.dondurulen), a, g, c);
}
yaz(D, 'toplam', '', '', '', agacta, gecmiste, acik);
console.log(`agactan silinmis ama dondurulmemis sir: `
  + `${sirlar.filter((s) => s.silinen !== null && s.dondurulen === null).length}/${sirlar.length}`);

// KI8: tarihce temizleme yalnizca erisilen kopyayi degistirir; dondurme her kopyayi
// degersiz kilar. Kopya sayilari kurgudur.
console.log('\ndeger islendikten sonra ulastigi kopyalar:');
const tutucular = [
  ['merkezi depo', 1, true],
  ['gelistirici klonu', 9, false],
  ['ayna ve yedek', 2, false],
  ['yapi calisma alani ve gunlugu', 4, false],
  ['paketlenmis yapi ciktisi', 3, false],
];
const E = [-32, 8, 18, 10];
yaz(E, 'tutucu', 'kopya', 'temizleme erisir', 'dondurme');
for (const [ad, n, erisir] of tutucular) yaz(E, ad, n, erisir ? 'evet' : 'hayir', 'evet');
const toplam = tutucular.reduce((a, [, n]) => a + n, 0);
const erisilen = tutucular.filter(([, , e]) => e).reduce((a, [, n]) => a + n, 0);
yaz(E, 'toplam', toplam, `${erisilen}`, `${toplam}`);
console.log(`tarihce temizlemenin disinda kalan kopya: ${toplam - erisilen}/${toplam}`);
sir                              giren  silinen  dondurulen   agacta  gecmiste    acik
saha imza anahtari                   7       19           -       12        53      53
rapor aktarim parolasi              12        -           -       48        48      48
portal oturum tuzu                   3       41          44       38        57      41
alim ust anahtari                   22       26           -        4        38      38
is emri geri cagirma anahtari       33       55          51       22        27      18
toplam                                                           124       223     198
agactan silinmis ama dondurulmemis sir: 2/5

deger islendikten sonra ulastigi kopyalar:
tutucu                             kopya  temizleme erisir  dondurme
merkezi depo                           1              evet      evet
gelistirici klonu                      9             hayir      evet
ayna ve yedek                          2             hayir      evet
yapi calisma alani ve gunlugu          4             hayir      evet
paketlenmis yapi ciktisi               3             hayir      evet
toplam                                19                 1        19
tarihce temizlemenin disinda kalan kopya: 18/19

Silmenin Kapatmadığı Şey

Üç sayı sütunu üç ayrı soruya karşılık geliyor ve üçü de aynı beş sır için farklı çıkıyor. Beş sır çalışma ağacında toplam 124 işlem boyunca görünüyor; aynı beş sır depo geçmişinde 223 işlem boyunca erişilebilir durumda; gerçekten açık kaldıkları süre ise 198 işlem. Ortadaki sütun ile soldaki arasındaki fark, silme işleminin ürettiği yanılsamanın büyüklüğüdür: doksan dokuz işlemlik bir aralık “temizlendi” diye kapatılmış görünüyor ama içerik geçmişte duruyor.

Satırlar tek tek okununca ölçü daha keskinleşiyor. Alım servisinin üst anahtarı çalışma ağacında yalnızca dört işlem kalmış — girdiği işlemden dört işlem sonra fark edilip silinmiş. Bu, hızlı bir düzeltme gibi görünür. Geçmiş sütunu aynı değer için 38 yazıyor ve açık sütunu da 38, çünkü değer hiç döndürülmemiş. Dört işlemlik bir görünürlük, otuz sekiz işlemlik bir açıklığa karşılık geliyor. Aynı kalıp saha imza anahtarında da var: on iki işlem ağaçta, elli üç işlem açık.

Son satır düzenin doğru sırasını gösteriyor. İş emri geri çağırma anahtarı 51’inci işlemde döndürülmüş, 55’inci işlemde silinmiş; açık kaldığı süre 18 işlem ve bu, beş sırrın en kısası. Ağaçta kalma süresi (22 işlem) açık kalma süresinden uzun olan tek satır budur. Önce döndürüp sonra temizlemek, ölçüyü tersine çeviren tek sıradır.

İkinci tablo bunun nedenini sayıyor. İşlenen bir değer yayımlandıktan sonra on dokuz kopyaya ulaşıyor: merkezî depo, dokuz geliştirici klonu, iki ayna ve yedek, dört yapı çalışma alanı ile günlüğü, üç paketlenmiş yapı çıktısı. Tarihçeyi yeniden yazmak bunlardan birine erişiyor; kalan on sekizi dokunulmadan duruyor. Klonların her biri ayrı bir işlemle güncellenmek zorundadır, yapı günlükleri çoğunlukla değiştirilemez, paketlenmiş çıktı zaten dağıtılmıştır. Döndürme sütunu ise on dokuzun on dokuzunda evet yazıyor — çünkü döndürme kopyayı silmez, kopyayı değersiz kılar. Değer dağıldıysa tek çıkar döndürmektir; tarihçe temizlemek onun yerini almaz, olsa olsa yeni bir kopya üretmeyi durdurur.

Aynı Kural, İki Ayrı Tarama

KI9 — bir tarama kuralı yalnızca taradığı kümedeki noktaları kapsar; anlık görüntü ile geçmiş iki ayrı kümedir. Aşağıdaki kural verilmiştir ve tartışılmaz: yirmi karakterden uzun ve karakter entropisi 3,6’nın üstünde olan değer işaretlenir. Ölçülen şey kuralın kalitesi değil, aynı kuralın iki ayrı küme üzerinde ne kapsadığıdır.

// depo/tarama.mjs — ayni kurgu depo gecmisinde desen taramasi (model, kendi basina kosar).
// Kural verilmistir: uzunluk >= 20 ve karakter entropisi >= 3.6 olan deger isaretlenir.
// Degerler kendi uretecimizle uretilir; hicbiri gercek bir sir bicimi tasimaz.
const ISLEM = 60;
let durum = 4703;
const rast = () => (durum = (durum * 1103515245 + 12345) % 2 ** 31) / 2 ** 31;
const ABC = 'abcdefghijkmnpqrstuvwxyzACDEFGHJKLMNPQRTUVWXYZ2346789';
const uret = (n) => Array.from({ length: n }, () => ABC[Math.floor(rast() * ABC.length)]).join('');

// [dosya, deger, gizli mi, giren islem, silinen islem]
const kalemler = [
  ['saha/ayar.mjs', uret(32), true, 7, 19],
  ['rapor/aktar.mjs', uret(28), true, 12, null],
  ['portal/oturum.mjs', uret(30), true, 3, 41],
  ['alim/kaynak.mjs', uret(14), true, 22, 26],
  ['is-emri/uc.mjs', uret(26), true, 33, 55],
  ['izleme/ornek.mjs', uret(28), false, 0, null],
  ['portal/simge.mjs', uret(40), false, 0, null],
  ['yapi/surum.mjs', uret(24), false, 5, null],
  ['katalog/kimlik.mjs', uret(22), false, 0, null],
  ['saha/sinama.mjs', uret(21), false, 9, 38],
  ['ceza/ayar.mjs', './veri/gecici/ceza', false, 0, null],
  ['bildirim/ornek.mjs', 'DEGISTIR-BENI', false, 0, null],
  ['uyelik/tur.mjs', 'abone-standart-tarife', false, 0, null],
];

const entropi = (d) => {
  const say = {};
  for (const c of d) say[c] = (say[c] ?? 0) + 1;
  return -Object.values(say).reduce((a, n) => a + (n / d.length) * Math.log2(n / d.length), 0);
};
const KURAL = (d) => d.length >= 20 && entropi(d) >= 3.6;
const varMi = (k, islem) => islem >= k[3] && (k[4] === null || islem < k[4]);

const yaz = (g, ...s) => console.log(s.map((v, i) =>
  (g[i] < 0 ? String(v).padEnd(-g[i]) : String(v).padStart(g[i]))).join(''));
const D = [-30, 10, 8, 11, 11, 13, 8];
yaz(D, 'tarama', 'taranan', 'bulgu', 'yakalanan', 'kacirilan', 'yanlis alarm', 'oran');

const olc = (ad, cift, tekil) => {
  const bulgu = tekil ? new Set(cift.filter(([k]) => KURAL(k[1])).map(([k]) => k[1])).size
    : cift.filter(([k]) => KURAL(k[1])).length;
  const dogru = tekil ? new Set(cift.filter(([k]) => KURAL(k[1]) && k[2]).map(([k]) => k[1])).size
    : cift.filter(([k]) => KURAL(k[1]) && k[2]).length;
  const gizliToplam = tekil ? new Set(cift.filter(([k]) => k[2]).map(([k]) => k[1])).size
    : cift.filter(([k]) => k[2]).length;
  yaz(D, ad, cift.length, bulgu, dogru, gizliToplam - dogru, bulgu - dogru,
    bulgu ? ((bulgu - dogru) / bulgu).toFixed(2) : '-');
};

const son = kalemler.filter((k) => varMi(k, ISLEM - 1)).map((k) => [k]);
const gecmis = [];
for (let i = 0; i < ISLEM; i++) for (const k of kalemler) if (varMi(k, i)) gecmis.push([k, i]);
olc('anlik goruntu (son islem)', son, false);
olc('tum gecmis', gecmis, false);
olc('tum gecmis + tekillestirme', gecmis, true);

const gizliGecmis = gecmis.filter(([k]) => k[2]).length;
console.log(`\nson islemde duran gizli kalem: ${son.filter(([k]) => k[2]).length}/5;`
  + ` gecmiste gorunen gizli kalem-islem cifti: ${gizliGecmis}`);
const kacan = kalemler.filter((k) => k[2] && !KURAL(k[1]));
console.log(`kuralin kacirdigi gizli kalem: ${kacan.map((k) => `${k[0]} (uzunluk ${k[1].length})`).join(', ')}`);
console.log(`gecmis taramasinin anlik goruntuye gore bulgu carpani: `
  + `${(gecmis.filter(([k]) => KURAL(k[1])).length / son.filter(([k]) => KURAL(k[1])).length).toFixed(1)}x`);
tarama                           taranan   bulgu  yakalanan  kacirilan yanlis alarm    oran
anlik goruntu (son islem)              8       5          1          0            4    0.80
tum gecmis                           568     384        120          4          264    0.69
tum gecmis + tekillestirme           568       9          4          1            5    0.56

son islemde duran gizli kalem: 1/5; gecmiste gorunen gizli kalem-islem cifti: 124
kuralin kacirdigi gizli kalem: alim/kaynak.mjs (uzunluk 14)
gecmis taramasinin anlik goruntuye gore bulgu carpani: 76.8x

Yanlış Alarmın Bedeli

Birinci satır kapsamayı en açık biçimde veriyor. Son işlemin çalışma ağacında yalnızca sekiz kalem var ve bunların yalnız biri gizli. Anlık görüntü taraması o biri buluyor, kaçırdığı yok ve mükemmel görünüyor. Oysa beş sırrın dördü zaten silinmiştir ve tarama onları hiç görmez. Kapsama oranı bu satırda 1/5’tir ve tarama bunu bildirmez; bildirdiği sayı yakaladığı bir bulgudur.

Tablonun altındaki satır bu 1/5’i başka bir açıdan yazıyor: geçmişte gizli bir kalemin göründüğü işlem çifti sayısı 124’tür. Aynı sayı birinci tablonun “ağaçta” sütununun toplamıdır ve iki ölçümün aynı modeli okuduğunu gösterir. Anlık görüntü taraması bu 124 çiftin yalnızca son işlemdekini görür.

İkinci satır aynı kuralı tüm geçmişe uyguluyor. Taranan kalem-işlem çifti 568’e, bulgu 384’e çıkıyor ve beş sırrın beşi de görünür hâle geliyor. Bulgu sayısı anlık görüntüye göre 76,8 kat artmış durumda. Yanlış alarm sayısı 264’tür ve oranı 0,69 — yani her üç bulgudan ikisi gizli olmayan bir değerdir. Bu oran kuralın kötülüğünden değil, aynı zararsız değerin altmış işlemde altmış kez sayılmasından geliyor.

Üçüncü satır bu çarpanı kaldırıyor. Bulgular içeriğe göre tekilleştirildiğinde 384 bulgu dokuza iniyor: dördü gizli, beşi yanlış alarm, oran 0,56. İncelenecek kalem sayısı iki büyüklük sırası küçülüyor ve kapsama hiç değişmiyor. Geçmiş taramasında ölçülmesi gereken şey bulgu sayısı değil, ayrı değer sayısıdır; aksi hâlde tarama kendi gürültüsünü ölçer.

Son satır kuralın sınırını yazıyor: alım servisinin üst anahtarı on dört karakter uzunluğunda ve eşiğin altında kaldığı için hiçbir taramada görünmüyor. Beş sırdan dördü kapsanıyor, biri dışarıda kalıyor. Bu, taramanın kendi ölçüsüyle gösterilemeyen bir eksiktir; kaçırdığını ancak başka bir yerden bilen biri sayabilir.

Yeni Sır Eklendiğinde

Üçüncü sütun bu dersin en keskin ayrımını taşıyor. Desen taraması bir kalıp değil, bir süzgeçtir: yarın eklenecek bir sır ancak eşiği geçerse kapsanır. Beş sırrın biri bugün eşiğin altındadır, dolayısıyla yeni bir değerin kapsanma olasılığı ölçülmüş değil, umulan bir şeydir. Eşiği düşürmek kapsamayı artırır ve yanlış alarmı büyütür; yanlış alarm oranı zaten 0,56’dır ve her artış inceleme işini çoğaltır.

Sırrın kaynak ağacına hiç girmediği kalıp bu sorunu farklı bir yerden çözüyor. Değer çalışma anında bir sır deposundan okunuyorsa kaynakta hiçbir zaman bir değer bulunmaz; kapsama, taramanın bulduğuna değil, kaynakta hiç değer olmamasına dayanır. Yeni bir sır eklendiğinde kapsama kendiliğinden sürer, çünkü değeri koda yazacak bir yer yoktur. Bu düzende tarama ortadan kalkmaz — kalıbın dışına çıkan noktayı bulmak için kalır — ama artık tek savunma değildir. İki savunmanın kapsaması aynı beş sırda ölçüldüğünde biri 4/5, öteki 5/5 verir ve aradaki bir satırlık fark, altmış işlemlik bir geçmişte 38 işlemlik bir açıklığa karşılık gelir.

Özet

  • Beş sır çalışma ağacında 124 işlem, depo geçmişinde 223 işlem görünüyor; gerçekten açık kaldıkları süre 198 işlem. Silme, doksan dokuz işlemlik bir aralığı kapatılmış gösteriyor.
  • Alım servisinin anahtarı ağaçta dört işlem kalmış ama hiç döndürülmediği için 38 işlem açık; ağaçta kalma süresi açık kalma süresinden kısa olduğu sürece silme bir ölçü vermez.
  • Önce döndürüp sonra temizleyen tek satır en kısa açıklığı üretti: 18 işlem.
  • İşlenen değer on dokuz kopyaya ulaşıyor; tarihçe temizleme birine erişiyor, on sekizi dışarıda kalıyor. Döndürme on dokuzunu birden değersiz kılıyor.
  • Anlık görüntü taraması beş sırdan yalnız birini görüyor; aynı kural tüm geçmişte beşini de buluyor ama bulgu 76,8 kat artıyor ve yanlış alarm oranı 0,69 oluyor. İçerik tekilleştirmesi bulguyu dokuza indiriyor, kapsamayı değiştirmiyor.
  • Desen taraması yeni sırrı ancak eşiği geçerse kapsıyor (4/5); değeri kaynağa hiç yazmayan kalıp yeni noktayı kendiliğinden kapsıyor.

Sonraki Adım

Bu ders sırrın kaynak ağacında ve depo geçmişinde bıraktığı izi saydı. Değer kaynaktan çıkarılıp bir depoya taşındığında bu iz kapanır — ama değer çalışma anında hâlâ süreçte durur ve süreç konuşur. Bir istek hata verdiğinde geriye dönen yanıt, bir işlem yapıldığında yazılan günlük satırı, bir çökme sonrası dosyaya düşen yığıt izi: hepsi sürecin içindeki değerlerin dışarı çıktığı noktalardır. Sonraki ders bu noktaları kalem olarak sayar — kaç yanıt yığıt izi taşıyor, kaç günlük satırı kimlik bilgisi ya da kişisel veri taşıyor, merkezî bir maskeleme katmanı kaçını kapatıyor ve kaç kalem dışarıda kalıyor.

İ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