---
title: 'Gizli Değer Yönetimi'
source: 'https://academia.sh/tr/kurslar/backend-uretim/gizli-deger-yonetimi'
course: 'Sunucu Güvenliği ve Üretime Alma'
language: tr
updated: '2026-08-17T18:06:49+00:00'
license: 'CC BY-SA 4.0'
---

# Gizli Değer Yönetimi

Üretimdeki gizli değerin üç ölçüsü: döndürme sırasında iki anahtarın birlikte geçerli olduğu pencerede kaç isteğin hangi sürümle doğrulandığı, temizleme adımı atlandığında sızan değerin ne kadar geçerli kaldığı ve kodda kalan sabit değeri arayan taramanın yanlış geçme ile yanlış kalma sayıları.

Önceki ders taşımayı sertleştirdi: dışarıdan gelen istek artık şifreli bir kanaldan giriyor ve
tarayıcıya ne yapabileceğini söyleyen başlıklar sunucu tarafında konuyor. Kanalın iki ucu
kapatıldığında geriye kanalın taşıdığı şey kalır. Ödünç sisteminin yedi servisi birbirini
çağırırken kim olduklarını bir **imza anahtarıyla** kanıtlar; katalog kimliği, ödeme anahtarı ve
bildirim belirteci de aynı sınıftandır. Bunlar **gizli değerdir** ve taşıma katmanı onları ancak
ağ üzerinde korur — durdukları yerde değil.

Bu değerlerin **test ortamına** dağıtımı Gizli Değer ve Veri Yönetimi dersinde ölçülmüştü: hangi
değerin ortama girdiği, ne kadar kapsam aldığı ve bir koşumun artefaktlarında kaç noktadan sızdığı
orada sayıldı. Üretim tarafının sorusu başkadır. Üretimde değer zaten girmiştir, kapsamı zaten
geniştir ve kimse onu koşum sonunda geri almaz. Burada ölçülen üç nicelik şudur: değer **kaç yerde
duruyor**, **döndürülürken** kaç istek kırılıyor, ve sızdığında **ne kadar süre** işe yarıyor.

**BG10 — yedi servis tek bir imza anahtarı halkasını paylaşır.** Bileti veren de doğrulayan da
aynı halkadan okur; halka sürümlüdür ve depo imzalayan sürüm ile doğrulayan sürüm kümesini ayrı
tutar. **BG11 — bir servis bileti 120 saniye geçerlidir** ve servis bileti bitene kadar tazelemez.
**BG12 — yeni değer servislere sırayla, 45 saniye aralıklarla ulaşır**; yedi servisin sonuncusu
döndürme anından 270 saniye sonra okur.

## Değerin Durduğu Yer

Depo, doğrulamanın hangi sürümleri kabul edeceğini **zamana bağlı** bir küme olarak verir. Döndürme
anından önce yalnız eski sürüm, pencere boyunca ikisi, pencere kapandıktan sonra yalnız yeni sürüm.

```js
// kasa.mjs — gizli deger deposu: surumlu anahtar halkasi, imzalama ve dogrulama kumesi
import { createHmac, timingSafeEqual } from 'node:crypto';

export const BILET_OMRU = 120;        // BG11: bir servis bileti 120 saniye gecerli
export const DONDURME_ANI = 300;      // yeni surumun uretildigi an
export const DAGITIM_ARALIGI = 45;    // BG12: servisler 45 saniye arayla yeni degeri okur
export const UFUK = 900;
export const SERVISLER = ['katalog', 'odunc', 'uyelik', 'bildirim', 'ceza', 'arama', 'raporlama'];

// Depo iki kumeyi ayri tutar: imzalayan tek surum, dogrulayan bir veya iki surum.
export function kasaAc(pencere) {
  const anahtar = { 1: 'v1-halka-4c9a1d', 2: 'v2-halka-77e5b0' };
  const kapanis = pencere === Infinity ? Infinity : DONDURME_ANI + pencere;
  return {
    dogrulayan: (t) => (t < DONDURME_ANI ? [1] : t < kapanis ? [1, 2] : [2]),
    imzala: (surum, govde) => createHmac('sha256', anahtar[surum]).update(govde).digest('base64url'),
    dogrula(t, govde, imza) {
      for (const surum of this.dogrulayan(t)) {
        const beklenen = Buffer.from(this.imzala(surum, govde));
        const gelen = Buffer.from(imza);
        if (beklenen.length === gelen.length && timingSafeEqual(beklenen, gelen)) return surum;
      }
      return 0;
    },
  };
}

// Degerin kac yerde durdugu: her servis hem surecinde hem zamanlanmis isinde okuyor.
export const YERLESIM = {
  dagitik: { yer: SERVISLER.length * 2, okuma: 0 },
  merkezi: { yer: 1, okuma: SERVISLER.length },
};
```

Son satırlar bu kursun üçüncü sorusunu karşılıyor: ayar kaç yerde tekrarlanıyor. Değer her servisin
sürecinde ve her servisin zamanlanmış işinde ayrı ayrı duruyorsa on dört yerdedir; çalışma anında
tek bir depodan okunuyorsa bir yerdedir ve yedi okuma noktası vardır. Fark, döndürmenin maliyetinde
görünür.

## Döndürme Penceresi

Aşağıdaki koşum gerçek bir doğrulama servisi ayağa kaldırır ve 900 saniyelik bir zaman çizgisini
beş saniyelik adımlarla dolaşır. Zaman sanaldır: her istek taşıdığı saati başlıkta bildirir, böylece
sayılar duvar saatine bağlı olmaz. Pencere genişliği taranır ve her genişlik iki kez koşar —
biri servislerin biletlerini olağan sırayla tazelediği hâl, öteki her servisin son eski bileti yeni
değeri okumasından bir saniye önce tazelediği **en kötü hizalama**.

```js
// dondurme.mjs — ortusme penceresi tarama: hangi anahtarla dogrulandi, kac istek reddedildi
import { createServer } from 'node:http';
import { kasaAc, BILET_OMRU, DONDURME_ANI, DAGITIM_ARALIGI, UFUK, SERVISLER, YERLESIM } from './kasa.mjs';

let kasa = kasaAc(0);
const sunucu = createServer((istek, yanit) => {
  const t = Number(istek.headers['x-saat']);
  const govde = istek.headers['x-bilet'];
  const verildi = Number(govde.split('.')[1]);
  const surum = kasa.dogrula(t, govde, istek.headers['x-imza'] ?? '');
  const [kod, sonuc] = surum === 0 ? [401, 'imza'] : t >= verildi + BILET_OMRU ? [401, 'sure'] : [200, surum];
  yanit.writeHead(kod, { 'content-type': 'application/json' });
  yanit.end(JSON.stringify({ sonuc }));
});
sunucu.listen(8951, '127.0.0.1');
const TABAN = 'http://127.0.0.1:8951/odunc';

// Servis i, DONDURME_ANI + i*DAGITIM_ARALIGI aninda yeni degeri okur; bileti bitene kadar tutar.
const okumaAni = (i) => DONDURME_ANI + i * DAGITIM_ARALIGI;
const SON_OKUMA = okumaAni(SERVISLER.length - 1);

// hizala: her servisin son v1 bileti, yeni degeri okumasindan bir saniye once tazelenir (en kotu hal).
async function kosum(pencere, hizala = false) {
  kasa = kasaAc(pencere);
  const bilet = SERVISLER.map(() => null);
  const hizalandi = SERVISLER.map(() => false);
  const sayac = { 1: 0, 2: 0, imza: 0, sure: 0 };
  let sonRet = null;
  for (let t = 0; t <= UFUK; t += 5) {
    const i = (t / 5) % SERVISLER.length;
    const kotu = hizala && !hizalandi[i] && bilet[i] !== null && t >= okumaAni(i);
    if (bilet[i] === null || t >= bilet[i].verildi + BILET_OMRU || kotu) {
      const verildi = kotu ? okumaAni(i) - 1 : t;
      const surum = verildi < okumaAni(i) ? 1 : 2;
      const govde = `${SERVISLER[i]}.${verildi}`;
      bilet[i] = { surum, govde, imza: kasa.imzala(surum, govde), verildi };
      hizalandi[i] ||= kotu;
    }
    const y = await fetch(TABAN, { headers: { 'x-saat': String(t), 'x-bilet': bilet[i].govde, 'x-imza': bilet[i].imza } });
    const { sonuc } = await y.json();
    sayac[sonuc] += 1;
    if (y.status === 401) sonRet = t;
  }
  // Sizmis eski surumle ufuktaki deneme: deger hala kapiyi aciyor mu.
  const govde = `arama.${UFUK}`;
  const sizan = await fetch(TABAN, { headers: { 'x-saat': String(UFUK), 'x-bilet': govde, 'x-imza': kasa.imzala(1, govde) } });
  return { ...sayac, sonRet, sizan: sizan.status };
}

const s = (x, n) => String(x).padStart(n);
console.log(`${'pencere'.padEnd(12)}${s('v1', 6)}${s('v2', 6)}${s('red', 6)}${s('son red', 9)}`
  + `${s('kotu red', 10)}${s('sizan v1', 10)}`);
for (const pencere of [0, 100, 200, 300, 400, Infinity]) {
  const r = await kosum(pencere);
  const k = await kosum(pencere, true);
  const ad = pencere === Infinity ? 'temizlemesiz' : `${pencere} sn`;
  console.log(`${ad.padEnd(12)}${s(r[1], 6)}${s(r[2], 6)}${s(r.imza + r.sure, 6)}`
    + `${s(r.sonRet ?? '-', 9)}${s(k.imza + k.sure, 10)}${s(r.sizan, 10)}`);
}
sunucu.close();

const gerekli = SON_OKUMA - DONDURME_ANI + BILET_OMRU;
console.log(`\nson okuma ${SON_OKUMA} sn, bilet omru ${BILET_OMRU} sn -> aritmetik alt sinir ${gerekli} sn`);
for (const [ad, y] of Object.entries(YERLESIM)) {
  console.log(`${ad}: deger ${y.yer} yerde duruyor, calisma aninda ${y.okuma} okuma, `
    + `yilda 4 dondurme ${y.yer * 4} elle adim eder`);
}
const gun = 24 * 60;
for (const donem of [90, 30, 7]) {
  console.log(`dondurme donemi ${donem} gun -> sizan anahtarin ortalama gecerliligi ${donem / 2} gun, `
    + `en kotu ${donem} gun; ayni anda sizan bilet ${BILET_OMRU / 60} dakika (${(donem * gun / (BILET_OMRU / 60)).toFixed(0)} kat kisa)`);
}
```

```
pencere         v1    v2   red  son red  kotu red  sizan v1
0 sn            60    85    36      555        51       401
100 sn          80    85    16      555        31       401
200 sn          90    85     6      555        15       401
300 sn          96    85     0        -         3       401
400 sn          96    85     0        -         0       401
temizlemesiz    96    85     0        -         0       200

son okuma 570 sn, bilet omru 120 sn -> aritmetik alt sinir 390 sn
dagitik: deger 14 yerde duruyor, calisma aninda 0 okuma, yilda 4 dondurme 56 elle adim eder
merkezi: deger 1 yerde duruyor, calisma aninda 7 okuma, yilda 4 dondurme 4 elle adim eder
dondurme donemi 90 gun -> sizan anahtarin ortalama gecerliligi 45 gun, en kotu 90 gun; ayni anda sizan bilet 2 dakika (64800 kat kisa)
dondurme donemi 30 gun -> sizan anahtarin ortalama gecerliligi 15 gun, en kotu 30 gun; ayni anda sizan bilet 2 dakika (21600 kat kisa)
dondurme donemi 7 gun -> sizan anahtarin ortalama gecerliligi 3.5 gun, en kotu 7 gun; ayni anda sizan bilet 2 dakika (5040 kat kisa)
```

## Pencerenin Okunması

İlk satır penceresiz döndürmedir ve bu kursun kuralının en açık örneğidir. Yeni sürüm üretilir
üretilmez doğrulama eskisini kabul etmeyi bırakır; **hiçbir yerde yapılandırma hatası yoktur**,
depo çalışır, imza doğrudur, servisler ayaktadır. Yine de 181 isteğin 36'sı reddedilir. Reddedilen
istekler döndürme anında değil, döndürmeden **255 saniye sonrasına kadar** sürer: son ret 555'inci
saniyededir. Sebep, elindeki bileti daha bitmeden atmayan servistir; en son okuyan servisin bileti
570'inci saniyeye kadar eski sürümle imzalanmıştır.

Pencere genişledikçe ret sayısı 36'dan 16'ya, 6'ya ve sıfıra iner. Sıfırın hangi genişlikte
geldiğine dikkat etmek gerekir: bu koşumda 300 saniye yetmiştir, ama aynı genişlik en kötü
hizalamada üç isteği reddeder. Koşumdan bağımsız nicelik tablonun altındaki satırdır — son okuma
anı ile döndürme anı arasındaki fark, artı bilet ömrü: 270 + 120 = **390 saniye**. Ölçülen değer
(300) doğru ayarı vermez; yalnızca o koşumun hizalamasını verir. Pencereyi ölçüme göre seçen bir
ekip, çizelge birkaç saniye kaydığında yeniden istek düşürür ve düşen istekler döndürmeden dört
dakika sonra geldiği için sebeple bağdaştırılmaz.

Son satır ise ölçünün tersinden yalan söylediği yerdir. **Temizlemesiz** düzende doğrulama iki
sürümü de süresiz kabul eder. Düşen istek sıfırdır, imza hatası sıfırdır, gösterge tablosu
temizdir; döndürme "başarılı" görünür. Sızan eski değerle 900'üncü saniyede yapılan deneme yine de
**200** alır — öteki beş satırda 401 alır. Yeni sürümün üretilmesi tek başına eskisini geçersiz
kılmaz; geçersiz kılan şey **kapatma adımıdır** ve o adım atlandığında hiçbir ölçü kötüleşmez.
Döndürmenin amacı budur ve döndürme tam olarak bu adımda sessizce başarısız olur.

## Sızan Değerin Ömrü

Bir değerin sızdığı fark edildiğinde sorulan soru "ne kadar süre işe yaradı" değil, "ne kadar süre
işe yarayacak" sorusudur ve yanıtı döndürme dönemine bağlıdır. Sızma anı dönem içinde herhangi bir
yere düşebileceğinden bekleneni dönemin yarısı, en kötüsü dönemin tamamıdır: doksan günlük dönemde
kırk beş gün, otuz günlükte on beş gün, yedi günlükte üç buçuk gün. Bu aritmetik, döndürmeyi
sıklaştırmanın neyi satın aldığını gösterir — kapıyı kapatmayı değil, **kapının açık kalacağı
süreyi**.

Aynı satırların ikinci yarısı asıl kaldıracı gösteriyor. Sızan şey anahtarın kendisi değil de
anahtarla üretilmiş bir biletse ömrü 120 saniyedir; doksan günlük dönemin altmış dört bin katı
kısa. Uzun ömürlü değeri az sayıda yerde tutup ondan kısa ömürlü bilet türetmek, döndürme
sıklığından bağımsız olarak açık kalma süresini dört büyüklük sırası kısaltır. Yerleşim satırları
bunun bedelini yazıyor: değer on dört yerde duruyorsa yılda dört döndürme elli altı elle adım eder
ve her adım kaçırılabilir; tek yerde duruyorsa dört adım eder ve yedi servis onu çalışma anında
okur.

## Kodda Kalan Değer

Yukarıdaki bütün aritmetik, değerin **yapılandırmada** durduğunu varsayar. Kodda duran bir değer
döndürüldüğünde geçersiz olmaz — kod değişene ve yayınlanana kadar eski değer imzalamaya devam
eder, dolayısıyla son okuma anı yayın süresi kadar geriye kayar ve gerekli pencere onunla birlikte
büyür. Bu yüzden kodda kalan sabit değeri aramak, döndürme düzeneğinin bir parçasıdır.

```js
// tarama.mjs — kodda kalan sabit degerin taranmasi: yanlis gecme ve yanlis kalma
// [dosya, satir, gercekten gizli mi]
const kaynak = [
  ['odunc/bilet.mjs', "const IMZA_ANAHTARI = 'v2-halka-77e5b0';", true],
  ['rapor/aktar.mjs', "const DEPO_PAROLASI = 'k3M-pW9-zQ4-vB7-nR2';", true],
  ['bildirim/gonder.mjs', "const ayar = { ust: 'T-4f8a1c9d2b6e0357a9c4f1b8' };", true],
  ['arama/dizin.mjs', "const yenile = 'Zq8Rv3Nw6Lp1Ke5Ty9Xu2Bd7Hm4';", true],
  ['uyelik/sinama.mjs', "const SINAMA_BELIRTECI = 'sb-9d31-77af-2c60';", true],
  ['katalog/kayit.mjs', "const KATALOG_KIMLIGI = 'ac-kutuphane-govde-2';", false],
  ['odunc/ayar.mjs', "const ANAHTAR_ADI = 'imza-anahtari-v2';", false],
  ['arayuz/ikon.mjs', "const IKON = 'iVBORw0KGgoAAAANSUhEUgAAAAgAAAAI';", false],
  ['ceza/ayar.mjs', "const gizliDizin = './veri/gecici/ceza';", false],
  ['bildirim/ornek.mjs', "const BELIRTEC_YERI = 'DEGISTIR-BENI-KURULUMDA';", false],
  ['uyelik/kimlik.mjs', "const uyeKimligi = '9f2c1a4e-77b0-4d31-8c6a-2e5b90f14d73';", false],
];

const deger = (satir) => (satir.match(/'([^']+)'/) ?? [, ''])[1];
const ad = (satir) => (satir.match(/(?:const|let)\s+(\w+)|(\w+)\s*:/) ?? [, ''])[1] ?? '';

function 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 AD_KALIBI = /anahtar|gizli|parola|belirtec|imza|sifre/i;
const IZINLI = [/^ac-/, /^DEGISTIR-BENI/];

const kurallar = {
  'ad kalibi': (s) => AD_KALIBI.test(ad(s)) && deger(s).length >= 8,
  'entropi': (s) => deger(s).length >= 20 && entropi(deger(s)) >= 3.6,
  'birlesim': (s) => kurallar['ad kalibi'](s) || kurallar['entropi'](s),
  'birlesim + izin listesi': (s) => kurallar.birlesim(s)
    && !IZINLI.some((r) => r.test(deger(s))) && !deger(s).includes('/'),
};

const s = (x, n) => String(x).padStart(n);
console.log(`${'kural'.padEnd(24)}${s('bulgu', 7)}${s('yakalanan', 11)}${s('yanlis gecme', 14)}${s('yanlis kalma', 14)}`);
for (const [kad, kural] of Object.entries(kurallar)) {
  const bulgu = kaynak.filter(([, satir]) => kural(satir));
  const dogru = bulgu.filter(([, , gizli]) => gizli).length;
  console.log(`${kad.padEnd(24)}${s(bulgu.length, 7)}${s(`${dogru}/5`, 11)}`
    + `${s(5 - dogru, 14)}${s(bulgu.length - dogru, 14)}`);
}

console.log('\nad kalibinin kacirdigi gercek degerler:');
for (const [dosya, satir, gizli] of kaynak) {
  if (gizli && !kurallar['ad kalibi'](satir)) {
    console.log(`  ${dosya.padEnd(22)} ad=${ad(satir).padEnd(8)} `
      + `uzunluk=${s(deger(satir).length, 2)} entropi=${entropi(deger(satir)).toFixed(2)}`);
  }
}
console.log('entropi kuralinin yanlis kaldigi zararsiz dizgeler:');
for (const [dosya, satir, gizli] of kaynak) {
  if (!gizli && kurallar.entropi(satir)) {
    console.log(`  ${dosya.padEnd(22)} uzunluk=${s(deger(satir).length, 2)} `
      + `entropi=${entropi(deger(satir)).toFixed(2)} izinli=${IZINLI.some((r) => r.test(deger(satir)))}`);
  }
}
```

```
kural                     bulgu  yakalanan  yanlis gecme  yanlis kalma
ad kalibi                     6        3/5             2             3
entropi                       5        2/5             3             3
birlesim                     10        5/5             0             5
birlesim + izin listesi       7        5/5             0             2

ad kalibinin kacirdigi gercek degerler:
  bildirim/gonder.mjs    ad=ayar     uzunluk=26 entropi=4.09
  arama/dizin.mjs        ad=yenile   uzunluk=27 entropi=4.75
entropi kuralinin yanlis kaldigi zararsiz dizgeler:
  katalog/kayit.mjs      uzunluk=20 entropi=3.78 izinli=true
  bildirim/ornek.mjs     uzunluk=23 entropi=3.76 izinli=true
  uyelik/kimlik.mjs      uzunluk=36 entropi=4.00 izinli=false
```

Ad kalıbı tek başına beş gerçek değerin üçünü bulur. Kaçırdığı ikisi listenin sonunda adıyla
duruyor: değişkenin adı `ayar` ve `yenile`. Adlandırma sözleşmesine dayanan bir tarama, sözleşmeye
uymayan satırı göremez ve gizli bir değeri koda sabitleyen kişi zaten sözleşmeyi izlememiştir.
Entropi kuralı bu ikisini yakalar ama kendi başına daha kötüdür: beşte iki. Kısa ve düzenli
biçimdeki değerler — on dokuz karakterlik parola, kısa çizgilerle bölünmüş bilet — eşiğin altında
kalır.

İkisinin birleşimi beş değerin beşini bulur ve bedeli beş yanlış kalmadır. Yanlış kalanların üçü
kural yazılarak elenebilir: açık katalog kimliğinin öneki, kurulumda değiştirilecek yer tutucu ve
eğik çizgi taşıyan dizin yolu. Kalan iki yanlış kalma elenemez, çünkü biri anahtarın **adını**
tutan bir sabittir, öteki bir üye kimliğidir; ikisi de gizli değere birebir benzer. Buradaki takas
kursun her yerinde aynıdır: yanlış geçmenin bedeli kodda kalan ve döndürülemeyen bir değerdir,
yanlış kalmanın bedeli ise iki satırlık elle incelemedir. Eşiği ikinci maliyete göre ayarlamak,
birinciyi ödemeyi göze almak demektir.

## Özet

- Üretimdeki gizli değerin üç ölçüsü kaç yerde durduğu, döndürülürken kaç istek kırdığı ve
  sızdığında ne kadar süre işe yaradığıdır; test ortamındaki ölçü olan sızma yüzeyi burada
  zaten en geniş hâlindedir.
- Penceresiz döndürme 181 isteğin 36'sını reddetti ve retler döndürmeden 255 saniye sonrasına
  kadar sürdü; hiçbir bileşen hata vermedi.
- Gerekli pencere ölçümden değil aritmetikten okunur: son okuma anı eksi döndürme anı artı bilet
  ömrü, bu düzende 390 saniye. Bu koşumda 300 saniye de sıfır ret verdi, en kötü hizalamada üç.
- Temizleme adımı atlandığında düşen istek sıfır kalır, gösterge temiz görünür ve sızan eski
  anahtar 900'üncü saniyede hâlâ 200 alır; döndürme yalnız kapatma adımıyla tamamlanır.
- Anahtarı az yerde tutup ondan 120 saniyelik bilet türetmek, sızan değerin ömrünü doksan günlük
  dönemin altmış dört bin katı kısaltır; değerin on dört yerde durması yılda elli altı elle adım,
  tek yerde durması dört adım eder.
- Sabit değer taramasında ad kalıbı beşte üç, entropi beşte iki yakaladı; birleşimi beşte beş
  yakaladı ve beş yanlış kalma üretti — üçü kuralla elenebilir, ikisi elenemez.

## Sonraki Adım

Bu dersin bütün ölçümleri kendi yazdığımız kodun içinde kaldı: anahtarı biz ürettik, biletin ömrünü
biz seçtik, taramanın eşiğini biz koyduk. Oysa isteği karşılayan kodun büyük bölümü bizim değildir.
Ödünç servisinin süreci ayağa kalktığında yüzlerce dosya yüklenir ve bunların çok azı ekibin
yazdığı satırlardır; her biri bir sürüm numarasına bağlıdır ve o numara bir gün değişir. Sonraki
ders bu bağımlılığı bir yapılandırma kararı olarak ele alır — yükseltmeyi ne sıklıkta yapmanın
biriken riskle kırılan sürüm arasında nasıl bir takas kurduğunu, üç ayrı politikayı aynı bağımlılık
ağacında koşturarak sayar.
