---
title: 'Parola Politikaları'
source: 'https://academia.sh/tr/kurslar/kimlik-ve-yetki/parola-politikalari'
course: 'Kimlik Doğrulama ve Yetkilendirme'
language: tr
updated: '2026-08-17T18:06:49+00:00'
license: 'CC BY-SA 4.0'
---

# Parola Politikaları

Karmaşıklık kurallarının kullanıcı davranışını nasıl daralttığı, dönemsel değiştirme kuralının kattığı gerçek fark, sızmış parola listesine karşı denetim ve karma öneki yöntemiyle parolayı açığa çıkarmayan sorgu.

Önceki dersin gruplama sorgusu tek bir şeyi gösterdi: sekiz üyeden üçü aynı dizgiyi seçmiş
ve o dizgi `kutuphane` idi. Tuz bu üç kaydın birbirine benzemesini engeller, yavaş karma
her birinin sınanmasını pahalılaştırır — ama hiçbiri seçimin kendisini değiştirmez. Sunucu
tarafındaki savunmaların bittiği yer, parola politikasının başladığı yerdir.

Politika, kullanıcıya hangi parolanın kabul edileceğini söyleyen kuraldır. Yazılması kolay
görünen bu kural, kullanılabilirlikle güvenliğin en doğrudan çarpıştığı yerdir: kural
sıkılaştıkça kullanıcı, kuralı en az çabayla karşılayan öngörülebilir bir yola girer. Bu
ders, hangi kuralın gerçekten işe yaradığını ölçmekle ilgilidir.

## Kuralın Öngördüğü Alan ve Kullanıcının Ürettiği Kalıp

Bir parola politikasının değeri, kuramsal olarak açtığı **arama alanıyla (search space)**
ölçülmez. Ölçüt, kural karşısında kullanıcıların gerçekte ürettiği kalıbın alanıdır.

"En az sekiz karakter, büyük harf, küçük harf, rakam ve simge zorunlu" kuralını ele alalım.
Kural, doksan dört karakterlik bir kümeden sekiz konum öngörür. Kullanıcının bu kuralı en
az çabayla karşılama yolu ise bellidir: bildiği bir kelimeyi alır, ilk harfini büyütür,
sonuna bir iki rakam ve bir simge ekler. Ortaya çıkan kalıbın alanı, kuralın öngördüğü
alandan çok daha küçüktür.

Aşağıdaki betik bu farkı dört politika için hesaplıyor. Kalıp alanları bir modeldir;
varsayımlar kodun içinde açıkça yazılıdır ve değiştirilerek yeniden hesaplanabilir.

```bash
cat > politika.mjs <<'EOF'
const bit = (n) => Math.log2(n);

const SOZLUK = 20000;      // kullanicinin sectigi taban kelime sayisi (model)
const politikalar = [
  {
    ad: "en az 8, dort tur karakter",
    kuramsal: 94 ** 8,
    // Kurali karsilayan en kisa yol: kelime + bas harf buyuk + 1-2 rakam + 1 simge
    kalip: SOZLUK * 1 * 110 * 10,
    aciklama: "kelime + Bas harf + rakam + simge",
  },
  { ad: "en az 12, kural yok", kuramsal: 26 ** 12,
    kalip: SOZLUK * SOZLUK * 100, aciklama: "iki kelime + rakam" },
  { ad: "en az 16, kural yok", kuramsal: 26 ** 16,
    kalip: SOZLUK ** 3 * 10, aciklama: "uc kelime + rakam" },
  { ad: "4 sozcuklu parola (2048 liste)", kuramsal: 2048 ** 4,
    kalip: 2048 ** 4, aciklama: "secim rastgele, kalip yok" },
];

console.log("politika                       | kuramsal | kalip    | kayip | kalibin kaynagi");
console.log("-------------------------------|----------|----------|-------|----------------------------");
for (const p of politikalar) {
  console.log(
    p.ad.padEnd(30) + " | " +
    (bit(p.kuramsal).toFixed(1) + " bit").padStart(8) + " | " +
    (bit(p.kalip).toFixed(1) + " bit").padStart(8) + " | " +
    (bit(p.kuramsal / p.kalip).toFixed(1)).padStart(5) + " | " + p.aciklama
  );
}

console.log("\n90 gunde bir degistirme kurali, kullanici sayaci ilerletiyorsa:");
for (const donem of [1, 4, 8, 20]) {
  const alan = SOZLUK * 110 * 10 * donem;
  console.log(`  ${String(donem).padStart(2)} donem sonra: ${bit(alan).toFixed(1)} bit ` +
    `(ilk donemden fark: ${(bit(alan) - bit(SOZLUK * 110 * 10)).toFixed(1)} bit)`);
}
EOF
node politika.mjs
```

```text
politika                       | kuramsal | kalip    | kayip | kalibin kaynagi
-------------------------------|----------|----------|-------|----------------------------
en az 8, dort tur karakter     | 52.4 bit | 24.4 bit |  28.0 | kelime + Bas harf + rakam + simge
en az 12, kural yok            | 56.4 bit | 35.2 bit |  21.2 | iki kelime + rakam
en az 16, kural yok            | 75.2 bit | 46.2 bit |  29.0 | uc kelime + rakam
4 sozcuklu parola (2048 liste) | 44.0 bit | 44.0 bit |   0.0 | secim rastgele, kalip yok

90 gunde bir degistirme kurali, kullanici sayaci ilerletiyorsa:
   1 donem sonra: 24.4 bit (ilk donemden fark: 0.0 bit)
   4 donem sonra: 26.4 bit (ilk donemden fark: 2.0 bit)
   8 donem sonra: 27.4 bit (ilk donemden fark: 3.0 bit)
  20 donem sonra: 28.7 bit (ilk donemden fark: 4.3 bit)
```

Birinci satır politikanın en yaygın biçimini gösteriyor: kural elli iki bit vaat ediyor,
kullanıcının kalıbı yirmi dört bit veriyor. Aradaki yirmi sekiz bitlik fark, kuralın
kullanıcıyı ittiği yönün sonucudur — kural karmaşıklığı zorunlu kıldığı için kullanıcı
karmaşıklığı en ucuz yerden, sondan ekler.

İkinci ve üçüncü satır uzunluğun ne yaptığını gösteriyor. Hiçbir karakter kuralı olmadan,
yalnız asgari uzunluğu artırmak kalıp alanını yirmi dört bitten otuz beşe, sonra kırk
altıya çıkarıyor. Uzunluk, kullanıcıyı daha fazla seçim yapmaya zorlar; karmaşıklık ise
aynı seçimi süslemeye zorlar.

Dördüncü satır sınırı gösteriyor: seçim kullanıcıya değil rastgele üretece bırakıldığında
kalıp diye bir şey kalmaz ve kuramsal alan gerçek alana eşit olur. Kırk dört bit,
birincisinden yirmi bit fazladır ve akılda tutulması ondan daha kolaydır.

## Dönemsel Değiştirme Kuralı

Çıktının ikinci bölümü, yaygın bir işletim kuralının bilançosudur. Doksan günde bir parola
değiştirmeyi zorunlu kılan kural, kullanıcı sondaki sayacı ilerlettiğinde yirmi dönem
sonunda toplam dört buçuk bit katar. Aynı kullanıcının aynı parolayı yirmi kez yazması
karşılığında elde edilen budur.

Karşı hanede duran maliyet ölçülebilir değil ama gözlenebilirdir: her dönem başında artan
sıfırlama istekleri, yazılı not alma davranışı ve sondaki sayacın öngörülebilirliği.
Dönemsel değiştirme kuralının savunulabilir tek biçimi koşulludur — parolanın sızdığına
dair bir belirti varsa değiştirme zorunlu kılınır. Takvime bağlı zorunlu değiştirme,
ölçülen katkısı kadar zarar üretir.

## Sızmış Parola Listesine Karşı Denetim

Kalıp tablosunun asıl sonucu şudur: kullanıcının seçimini kurallarla yönlendirmek zayıf bir
araçtır. Güçlü araç, seçimi doğrudan reddetmektir. Daha önce sızmış olduğu bilinen bir
parola, kaç kural karşılarsa karşılasın, aday listelerinin içindedir ve reddedilmelidir.

Bu denetimin uygulanmasında bir sorun vardır: liste büyüktür ve kullanıcının seçtiği
parolanın listeyi tutan tarafa gönderilmesi kabul edilemez. Çözüm, sorguyu parolanın
kendisi yerine karmasının bir **öneki (prefix)** üzerinden yapmaktır. Sunucu, önekle
eşleşen tüm kayıtları döndürür; kullanıcının parolasının o küme içinde olup olmadığına
istemci kendi belleğinde karar verir. Sunucunun öğrendiği tek şey önektir; hangi kaydın
arandığı belirsiz kalır. Bu belirsizliğe **k-anonimlik (k-anonymity)** denir ve `k`, dönen
kümedeki kayıt sayısıdır.

Önek uzunluğu bir ödünleşimdir. Kısa önek daha büyük kova döndürür — daha çok gizlilik,
daha çok veri aktarımı. Uzun önek tersini yapar. Aşağıdaki betik bu ödünleşimi yerel bir
liste üzerinde ölçüyor.

```bash
cat > onek.mjs <<'EOF'
import { createHash } from "node:crypto";

const kok = ["kutuphane","kitap","okuma","sube","deniz","cinar","yaz","kis","uye","odunc",
             "masa","raf","kart","ceza","iade","katalog","salon","kalem","defter","not"];

function* liste(n = 200000) {                     // yerel, uretilmis ornek liste
  yield* ["kutuphane", "sahil-subesi", "odunc123"];
  for (let i = 0; i < n; i++) {
    yield `${kok[i % 20]}-${kok[Math.floor(i / 20) % 20]}-${Math.floor(i / 400) % 500}`;
  }
}

const karmalar = [...liste()].map((p) =>
  createHash("sha1").update(p).digest("hex").toUpperCase());
console.log(`yerel liste: ${karmalar.length.toLocaleString("tr-TR")} kayit`);

console.log("\nonek | kova sayisi | ortalama kova | en buyuk kova | sunucunun gordugu");
console.log("-----|-------------|---------------|---------------|-------------------");
for (const uzunluk of [2, 3, 4, 5]) {
  const kova = new Map();
  for (const h of karmalar) {
    const o = h.slice(0, uzunluk);
    kova.set(o, (kova.get(o) ?? 0) + 1);
  }
  const boyutlar = [...kova.values()];
  const ort = boyutlar.reduce((a, b) => a + b, 0) / boyutlar.length;
  const enbuyuk = boyutlar.reduce((a, b) => (b > a ? b : a), 0);
  console.log(
    ` ${uzunluk}   | ${String(kova.size).padStart(11)} | ${ort.toFixed(1).padStart(13)} | ` +
    `${String(enbuyuk).padStart(13)} | ${(uzunluk * 4)} bit / 160 bit`
  );
}
EOF
node onek.mjs
```

```text
yerel liste: 200.003 kayit

onek | kova sayisi | ortalama kova | en buyuk kova | sunucunun gordugu
-----|-------------|---------------|---------------|-------------------
 2   |         256 |         781.3 |           843 | 8 bit / 160 bit
 3   |        4096 |          48.8 |            74 | 12 bit / 160 bit
 4   |       62463 |           3.2 |            13 | 16 bit / 160 bit
 5   |      181985 |           1.1 |             5 | 20 bit / 160 bit
```

Tablo önek uzunluğunun liste boyutuna bağlı seçildiğini gösteriyor. İki yüz bin kayıtlık bu
listede dört karakterlik önek ortalama üç kayıt döndürüyor; bu, k-anonimliğin anlamlı
olmadığı bir kova boyutudur. Üç karakter, ortalama kırk dokuz kayıtlık kova verir ve sunucu
yüz altmış bitlik karmanın yalnız on ikisini görür. Liste milyarlarca kayda çıktığında aynı
kova boyutuna beş karakterlik önekle ulaşılır — kural, önek uzunluğunun kova boyutunu
hedeflenen `k` değerinde tutacak biçimde seçilmesidir.

Buradaki karma fonksiyonunun seçimi ayrı bir noktadır. Bu hesap parola saklamak için değil,
kayıtları önek kovalarına dağıtmak için yapılır; hız burada bir kusur değil gerekliliktir.
Önceki iki dersin yavaş karma kuralı saklama yolunda geçerlidir, bu dizin anahtarında
değil.

## Sorgunun Çalıştırılması

Aşağıdaki blok yerel bir aralık servisi ayağa kaldırıyor ve iki parolayı denetliyor:
önceki dersteki üyelerin paylaştığı `kutuphane` ile U-1001'in seçtiği `deniz-kabugu-7`.
İstekte giden tek şey üç karakterlik önektir.

```bash
cat > aralik-sunucu.mjs <<'EOF'
import { createServer } from "node:http";
import { createHash } from "node:crypto";

const kok = ["kutuphane","kitap","okuma","sube","deniz","cinar","yaz","kis","uye","odunc",
             "masa","raf","kart","ceza","iade","katalog","salon","kalem","defter","not"];
function* liste(n = 200000) {
  yield* ["kutuphane", "sahil-subesi", "odunc123"];
  for (let i = 0; i < n; i++) {
    yield `${kok[i % 20]}-${kok[Math.floor(i / 20) % 20]}-${Math.floor(i / 400) % 500}`;
  }
}

const ONEK = 3;                                   // bu liste boyutuna gore secildi
const kova = new Map();
for (const p of liste()) {
  const h = createHash("sha1").update(p).digest("hex").toUpperCase();
  const o = h.slice(0, ONEK);
  if (!kova.has(o)) kova.set(o, []);
  kova.get(o).push(h.slice(ONEK));
}

createServer((istek, yanit) => {
  const yol = new URL(istek.url, "http://yerel").pathname;
  if (yol === "/saglik") return yanit.writeHead(200).end("hazir\n");
  const eslesme = /^\/aralik\/([0-9A-F]{3})$/.exec(yol);
  if (!eslesme) return yanit.writeHead(404).end("");
  yanit.writeHead(200, { "content-type": "text/plain" });
  yanit.end((kova.get(eslesme[1]) ?? []).join("\n") + "\n");
}).listen(8493, "127.0.0.1");
EOF
node aralik-sunucu.mjs & sunucu=$!
until curl -sf http://127.0.0.1:8493/saglik > /dev/null; do :; done

karma() { node -e 'const {createHash}=require("node:crypto");
  process.stdout.write(createHash("sha1").update(process.argv[1]).digest("hex").toUpperCase())' "$1"; }

for parola in kutuphane deniz-kabugu-7; do
  tam=$(karma "$parola"); onek=${tam:0:3}; kuyruk=${tam:3}
  curl -s "http://127.0.0.1:8493/aralik/$onek" -o kova.txt
  echo "parola      : $parola"
  echo "  giden onek: $onek   (tam karmanin ilk 3 karakteri)"
  echo "  donen kova: $(wc -l < kova.txt | tr -d ' ') kuyruk"
  if grep -qx "$kuyruk" kova.txt; then echo "  sonuc     : listede VAR, reddedilir"
  else echo "  sonuc     : listede yok, kabul edilir"; fi
done

kill $sunucu
rm -f kova.txt aralik-sunucu.mjs
```

```text
parola      : kutuphane
  giden onek: 2E5   (tam karmanin ilk 3 karakteri)
  donen kova: 51 kuyruk
  sonuc     : listede VAR, reddedilir
parola      : deniz-kabugu-7
  giden onek: 5B8   (tam karmanin ilk 3 karakteri)
  donen kova: 54 kuyruk
  sonuc     : listede yok, kabul edilir
```

Kararı veren taraf istemcidir; sunucu yalnız bir kova döndürür ve hangi kaydın sorulduğunu
bilmez. Önek değerleri listeye ve karma fonksiyonuna bağlıdır, kova boyutları da öyle;
akış değişmez. Aynı yordam kendi altyapınızda tutulan bir listeyle de çalışır — o durumda
liste zaten sizdedir ve önek katmanı, denetimi yapan servisin parolayı hiç görmemesini
sağlar.

Denetimin nerede yapılacağı ayrı bir karardır. Kayıt ve parola değiştirme akışlarında
denetim zorunludur. Giriş akışında da yapılabilir: kullanıcı doğru parolayla girdiğinde
parola elde olur ve listeye karşı denetlenebilir; listede çıkarsa kullanıcıya değiştirme
istemi gösterilir. Bu, önceki derslerdeki parametre yükseltmesiyle aynı yerde yapılan bir
işlemdir.

## Politikanın Yazılı Hâli

Buraya kadarki ölçümler tek bir politikaya varır.

**Asgari uzunluk konur, azami uzunluk konmaz.** Sekiz karakterlik alt sınır düşüktür; on
iki daha savunulabilirdir. Üst sınır ise gereksizdir — karma zaten sabit uzunlukta çıktı
üretir. Kırk karakterde kesen bir alan, parola yöneticisi kullanan kullanıcıyı elle yazmaya
zorlar.

**Karakter türü zorunluluğu konmaz.** Ölçülen etkisi, kullanıcıyı öngörülebilir bir kalıba
itmektir. Kuralın yerini uzunluk ve liste denetimi alır.

**Tüm karakterler kabul edilir.** Boşluk, noktalama ve Türkçe harfler dâhil. Kısıtlanan her
karakter kümesi, kullanıcının seçim alanını daraltır. Önceki derste kurulan normalleştirme
adımı bu kabulü güvenli kılar.

**Yapıştırma engellenmez.** Yapıştırmayı engelleyen alan, parola yöneticisi kullanımını
imkânsızlaştırır ve kullanıcıyı akılda tutulabilir — yani zayıf — parolaya iter.

**Geri bildirim yazarken verilir.** Kullanıcı parolayı yazarken kabul edilip edilmeyeceğini
görmelidir; gönderdikten sonra reddedilen bir form, kullanıcıyı kuralı en az çabayla
karşılamaya iter.

**Liste denetimi zorunludur.** Sızmış parola listesine karşı denetim, tüm karakter
kurallarının toplamından daha etkilidir ve yukarıdaki yöntemle parolayı açığa çıkarmadan
yapılır.

## Özet

- Politikanın değeri kuramsal arama alanıyla değil, kural karşısında kullanıcıların
  ürettiği kalıbın alanıyla ölçülür.
- Karakter türü zorunluluğu kalıp alanını daraltır; asgari uzunluğu artırmak aynı kullanıcı
  davranışında daha geniş alan üretir.
- Takvime bağlı dönemsel değiştirme yirmi dönemde dört buçuk bit katar; savunulabilir
  biçimi, sızıntı belirtisine bağlı koşullu değiştirmedir.
- Sızmış parola listesine karşı denetim, kullanıcının seçimini kurallarla yönlendirmekten
  daha etkilidir.
- Karma önekiyle sorgulama, parolayı ve tam karmayı açığa çıkarmadan denetim yapar; önek
  uzunluğu, kova boyutunu hedeflenen `k` değerinde tutacak biçimde seçilir.

## Sonraki Adım

Parola ne kadar iyi seçilirse seçilsin unutulur ve her sistem bir kurtarma yolu sunmak
zorundadır. Bu yol, kimlik doğrulamanın tamamını atlayan ikinci bir kapıdır: doğru
kurulmazsa, parolayı hiç bilmeyen birinin hesaba girmesine yeter. Sonraki ders sıfırlama
akışının saldırı yüzeyini ele alıyor — belirtecin tek kullanımlık, kısa ömürlü ve karma
olarak saklanması, kullanıcı numaralandırmasına karşı aynı yanıtın döndürülmesi ve
sıfırlamanın oturumlar üzerindeki etkisi.
