İçeriğe atla
0 XP 0
16 dkderinleşmeyle 18 dk50 XP8 etkinlik

Parola saklama: tuz ve modern özetleme

Bu derste
  • Parolayı neden şifrelemediğini, tuzlu ve yavaş özetle nasıl sakladığını, Argon2id ayarını, eski özetten göçü ve sızıntı kara listesini öğrenirsin.
  • Bu derste tuzun neden zorunlu olduğunu, bcrypt ve Argon2id'in yavaş çalışmayı neden kasıtlı seçtiğini çözer, eski algoritmadan geçiş stratejisini öğrenirsin.

Puan bütün etkinlikleri cevaplayınca hesaba yazılır. Bu dersi tamamlayınca +50 XP alacaksın. Giriş yapmadan ilerlersen puan yalnız bu tarayıcıda durur.

Bir gün kullanıcı tablonun sızacağını varsay. Bu karamsarlık değil, parola saklamanın başlangıç noktasıdır.

Bir yedek dosyası yanlış yere düşer, bir SQL enjeksiyonu tabloyu okur ya da eski bir çalışanın erişimi kapanmaz. O gün saldırganın elinde parola sütunu olur. Senin işin, o sütunu değersiz kılmaktır.

Değersiz, saldırganın parolaları makul sürede geri bulamaması demektir. Bu derste Altay Kargo'nun kullanıcı tablosu üzerinden ilerlersin. Önce özetleme ile tuzu, sonra yavaş algoritmayı görürsün. Ardından Argon2id'i komut satırında ve kodda çalıştırır, eski özetlerden göçü ve parola politikasını kurarsın.

Şifreleme değil, tuzlu özet

Parola saklamada iki yol vardır: şifreleme ve özetleme. Şifreleme (encryption) tersine çevrilebilir; doğru anahtarla şifreli metin yeniden düz parolaya döner. Parola için bu tehlikeli bir özelliktir.

Veritabanı sızarsa anahtar genelde aynı sistemde durur ve saldırgan bütün parolaları tek adımda çözer. Özetleme (hash) ise tek yönlüdür. Parolayı sabit uzunlukta bir dizgeye dönüştürür, dizgeden parolaya geri dönmek pratikte imkânsızdır.

Girişte sistem, yazılan parolayı aynı fonksiyonla yeniden özetler ve iki özeti karşılaştırır; parolanın kendisini hiç saklamaz. Şifreleme çekici görünür, unutulan parolayı geri okumaya olanak tanır gibi hissettirir. Oysa doğru ürün kararı, kullanıcıya parolasını asla geri göstermemek ve yalnız sıfırlama akışı sunmaktır.

Tek başına özetleme yetmez. Aynı parolayı seçen iki kullanıcı, tuzsuz bir sistemde birebir aynı özete sahip olur. Bu eşleşme, saldırganın önceden hesaplayıp hazır tuttuğu gökkuşağı tablosuyla (rainbow table) parolayı saniyeler içinde bulmasına yeter. Tuz (salt), her kullanıcı için ayrı üretilen rastgele bir değerdir.

Parolayla birlikte özetlenir ve özetin yanında düz hâlde saklanır. Tuz gizli değildir; amacı görünmezlik değil benzersizliktir. Aynı parola artık her kullanıcıda farklı bir özet üretir ve hazır tablo işe yaramaz. Tuz ayrı bir sütunda ya da özetin başında durabilir.

Tuzun işe yaraması için üç koşul gerekir. Birincisi, tuz kriptografik olarak güvenli bir rastgele sayı üretecinden (CSPRNG) gelir. Python'da bu secrets ya da os.urandom demektir, random modülü değil.

İkincisi, yeterince uzundur; 16 bayt yaygın ve güvenli bir seçimdir. Üçüncüsü, her parola değişiminde yeniden üretilir. Sık görülen hata, bütün kullanıcılar için tek bir sabit tuz kullanmaktır.

Sabit tuz hazır tabloları bozar, ama saldırgan yeni tabloyu bir kez hesaplayıp bütün kayıtlara uygular. İyi haber şu: bcrypt ve Argon2id kütüphaneleri tuzu kendileri üretir ve özet dizgesine gömer. Tuzu elle üretmek çoğu zaman hatanın başladığı yerdir.

Etkinlik 1 / 8

Aşağıdaki saklama yöntemlerini güvenli ve güvensiz olarak ayır.

Önce bir seçeneğe, sonra aşağıdaki uygun kutuya bas. İstersen seçeneği kutuya sürükleyip bırak. Yerini değiştirmek için aynı işlemi tekrarla.

0/4 seçenek yerleşti.

Hız, saldırganın yanında durur

Tuz tek başına da yetmez, çünkü MD5 ya da tek geçişli SHA-256 gibi algoritmalar saniyede milyarlarca deneme yapacak kadar hızlıdır. Ekran kartları bu hızı kolayca yakalar. Parola özetlemeye özel kurulmuş fonksiyonlar bilerek yavaş ve bellek aç çalışır.

bcrypt, iş faktörü (cost factor) adında ayarlanabilir bir zorluk taşır; faktör arttıkça her deneme daha uzun sürer. Argon2id ise hem işlemciyi hem belleği zorlar, bu da özel donanımla hızlandırmayı pahalı kılar. Doğru faktör sabit değildir. Her ekip kendi sunucusunda ölçer; OWASP, bir özet hesabının genel kural olarak bir saniyenin altında kalmasını ister.

Farkın büyüklüğünü parola kırma aracı hashcat'in ölçüm modunda görürsün. hashcat -b komutu, seçtiğin algoritma için kartın saniyede kaç aday özet hesapladığını ölçer. -m 0 MD5'i, -m 3200 bcrypt'i seçer.

Aşağıdaki satırlar tek bir güncel oyun ekran kartında yayımlanmış bir ölçümden alındı. Aynı komutu kendi lab makinende çalıştırıp kendi sayını da görebilirsin; komut hiçbir özeti kırmaz, yalnız hız ölçer. Ölçtüğün sayı, sızan bir tabloya karşı saldırganın gerçek hızına yakındır.

$ hashcat -b -m 0
* Hash-Mode 0 (MD5)
Speed.#1.........:   164.1 GH/s (12.91ms) @ Accel:128 Loops:1024 Thr:128 Vec:8

$ hashcat -b -m 3200
* Hash-Mode 3200 (bcrypt $2*$, Blowfish (Unix)) [Iterations: 32]
Speed.#1.........:   184.0 kH/s (50.22ms) @ Accel:4 Loops:32 Thr:24 Vec:1
Tek bir RTX 4090 kartında yayımlanmış hashcat ölçümünden kısaltılmış satırlar. Sayılar donanıma göre değişir.

Satırları sırayla oku. İlk ölçümde kart MD5 için saniyede 164,1 milyar (GH/s) aday dener.

İkinci ölçümde bcrypt için saniyede 184 bin (kH/s) aday dener; aradaki fark yaklaşık 900 bin kattır. Iterations: 32 ibaresi, ölçümün iş faktörü 5 ile yapıldığını gösterir, çünkü 2 üzeri 5 eşittir 32. Faktör her bir arttığında iş iki katına çıkar.

Şimdi savunma sorusunu sor: sızan tabloda saldırgan saniyede kaç deneme yapar? MD5'te bir milyar adaylık bir sözlük bir saniyenin altında biter. Faktör 12 bcrypt'te aynı sözlük tek kartta sekiz günü aşar. Tuz yüzünden bu bedeli her kullanıcı için ayrıca öder.

Bu fark üretimde somut sonuç doğurur. Tuzsuz ya da hızlı algoritmayla saklanmış büyük bir parola tablosu sızdığında saldırganlar özetlerin büyük bölümünü saatler içinde toplu olarak kırar. Aynı sızıntıda Argon2id ya da bcrypt ile saklanmış hesaplar haftalarca, hatta hiç kırılmadan kalabilir. Fark, kullanıcıya duyurulan olay raporunda bile görünür.

Bazı ekipler parolaların tuzlu bcrypt ile saklandığını ve riskin düşük olduğunu söyleyebilir. Zayıf algoritma kullananlar ise bütün kullanıcıları zorunlu parola sıfırlamaya çağırır. Faktör seçerken yoğun saatteki eşzamanlı giriş sayısını da hesaba kat; sunucunun kaldıracağı en yüksek faktörü seç.

Etkinlik 2 / 8

Altay Kargo'nun kayıt ucunda parolayı yanlış saklayan satırı bul.

Zafiyetli satıra tıkla.

Etkinlik 3 / 8

Yayımlanmış ölçümde kart, bcrypt iş faktörü 5 ile saniyede 184.000 aday deniyordu. Aynı kart iş faktörü 12 ile saniyede yaklaşık kaç aday dener?

Tahminini kaydır, sonra gönder.

05000

Argon2id'i komut satırında tanı

Argon2id parametreleri üç eksende ayarlanır: m bellek miktarını (KiB), t yineleme sayısını, p paralellik derecesini belirler. OWASP Password Storage Cheat Sheet en az m=19456 (19 MiB), t=2, p=1 önerir. Aynı korumayı m=47104 (46 MiB), t=1, p=1 ile de kurabilirsin; bellek artınca yineleme azalır. Argon2id yoksa sıra scrypt'e gelir (N=2^17, r=8, p=1).

bcrypt'te iş faktörü en az 10 olmalıdır. FIPS 140 uyumu zorunluysa PBKDF2-HMAC-SHA256 600.000 yinelemeyle kullanılır. Bu sayılar zamanla eskir, donanım hızlandıkça öneriler yukarı çekilir.

Referans Argon2 uygulaması bir komut satırı aracıyla gelir. Parolayı standart girdiden, tuzu ilk argümandan okur. -m belleği ikinin üssü olarak alır: -m 15, 2^15 KiB yani 32 MiB demektir.

$ echo -n "mavi-kamyon-gece-yola-cikar" | argon2 tuzdegeri -id -t 2 -m 15 -p 1
Type:           Argon2id
Iterations:     2
Memory:         32768 KiB
Parallelism:    1
Hash:           98139684b03b61a21b5796e58afec4a21dd751d87a0e7732190a6171d7401bf1
Encoded:        $argon2id$v=19$m=32768,t=2,p=1$dHV6ZGVnZXJp$mBOWhLA7YaIbV5bliv7Eoh3XUdh6DncyGQphcddAG/E
0.080 seconds
Verification ok
Aynı parola ve aynı tuzla sen de birebir aynı çıktıyı alırsın. Süre makineye göre değişir.

Çıktıyı satır satır oku. Type, Iterations, Memory ve Parallelism verdiğin ayarları doğrular; 15 değerinin 32768 KiB'a dönüştüğünü görürsün. Hash, 32 baytlık ham özetin onaltılık gösterimidir. Saklayacağın satır Encoded'dur ve PHC dizge biçimini izler.

Dizge dolar işaretleriyle beş alana bölünür: algoritma adı (argon2id), sürüm (v=19, yani Argon2 1.3), parametreler, Base64 ile kodlanmış tuz ve Base64 ile kodlanmış özet. Base64 burada dolgu karakteri (=) taşımaz. Son satır, aracın özeti hemen yeniden doğruladığını söyler. Aynı parolayı baskatuz7 tuzuyla özetlersen Encoded satırının tuz alanı YmFza2F0dXo3 olur ve özet tamamen değişir.

Derinleş:Argon2 nereden geldi

2013'te kriptografi topluluğu Password Hashing Competition (PHC) adında açık bir yarışma başlattı. Amaç, bcrypt ve PBKDF2'den daha iyi bir parola özetleme fonksiyonu bulmaktı. Yarışma, şifreleme standartlarını seçen açık yarışmalara benzer işledi: adaylar yayımlandı, herkes saldırı denedi, zayıf tasarımlar elendi.

Temmuz 2015'te Argon2 kazanan ilan edildi, dört finaliste de özel takdir verildi. Argon2'nin üç türü vardır. Argon2d belleğe veriye bağlı erişir; ekran kartı saldırısına çok dayanıklıdır ama yan kanal zamanlama saldırısına açıktır.

Argon2i veriden bağımsız erişir; yan kanala dayanır ama daha çok tur ister. Argon2id ikisini karıştırır ve parola saklama için önerilen türdür. Algoritma Eylül 2021'de RFC 9106 ile standartlaştı. RFC, Argon2id desteğini her uygulamada zorunlu tutar ve iki profil önerir: 2 GiB bellekli birinci seçenek ile 64 MiB bellekli ikinci seçenek.

Etkinlik 4 / 8

Lab makinende mavi-kamyon-gece-yola-cikar parolasını tuzdegeri tuzuyla Argon2id türünde, 2 yineleme, 32 MiB bellek ve 1 iş parçacığıyla özetleyen komutu yaz. Parolayı echo -n ile borudan ver.

ogrenci@lab

Etkinlik 5 / 8

Kayıtlı dizge $argon2id$v=19$m=32768,t=2,p=1$dHV6ZGVnZXJp$mBOW... biçiminde. Tuz alanını çöz. Tuz hangi metin?

Araçları sırayla dene. Yanlış araç bozuk çıktı verir.

dHV6ZGVnZXJp

Kodda özetle, doğrula, yükselt

Uygulama kodunda komut satırı aracını değil, bir kütüphaneyi kullanırsın. Python'da yaygın seçim argon2-cffi'dir. PasswordHasher sınıfı tuzu kendisi üretir, ayarları dizgeye yazar ve doğrulamayı güvenli biçimde yapar.

Varsayılan ayarları RFC 9106'nın düşük bellek profilinden gelir: t=3, m=64 MiB, p=4. Bu değerler OWASP'ın alt sınırından güçlüdür. Kütüphane ayarı dizgenin içine yazdığı için eski ve yeni ayarlı kayıtlar aynı tabloda yan yana yaşayabilir. Aşağıdaki kod Altay Kargo'nun kayıt ve giriş akışını birlikte gösterir.

from argon2 import PasswordHasher
from argon2.exceptions import VerifyMismatchError

ph = PasswordHasher()  # RFC 9106 düşük bellek profili: t=3, m=64 MiB, p=4

def kayit_ol(kullanici_adi, parola):
    ozet = ph.hash(parola)  # tuzu kendisi üretir, PHC dizgesi döner
    db.kullanici.ekle(ad=kullanici_adi, parola_ozeti=ozet)

def giris_yap(kullanici_adi, parola):
    kayit = db.kullanici.bul(ad=kullanici_adi)
    try:
        ph.verify(kayit.parola_ozeti, parola)
    except VerifyMismatchError:
        return False
    if ph.check_needs_rehash(kayit.parola_ozeti):
        kayit.parola_ozeti = ph.hash(parola)  # ayarı sessizce yükselt
        db.kullanici.guncelle(kayit)
    return True
argon2-cffi ile kayıt, doğrulama ve ayar yükseltme.

Kodu satır satır oku. ph.hash() her çağrıda yeni bir 16 baytlık tuz üretir ve sonucu PHC dizgesi olarak döner; veritabanına yazdığın tek şey bu dizgedir. ph.verify() dizgedeki tuzu ve ayarları okur, girilen parolayı aynı ayarla özetler ve sonucu karşılaştırır.

Eşleşme yoksa VerifyMismatchError fırlatır, kod da girişi reddeder. check_needs_rehash() kayıtlı ayarın güncel ayardan farklı olup olmadığına bakar.

Komut satırında ürettiğin t=2, 32 MiB dizgesi için True döner. O anda elinde doğrulanmış düz parola vardır. Kaydı yeni ayarla yeniden özetler ve güncellersin. Böylece ayarı yükseltmek için kimseden parola istemezsin.

Özetleri kendin karşılaştırırsan bir tuzağa düşebilirsin. Sıradan eşitlik işleci (==) ilk farklı baytta durur. Doğru tahmin edilen her bayt karşılaştırmayı biraz uzatır.

Çok sayıda ölçümle bu fark bir zamanlama sızıntısına (timing leak) dönüşebilir. Kütüphanenin verify fonksiyonu bu yüzden sabit zamanlı karşılaştırma yapar. Bir API anahtarını ya da sıfırlama jetonunu elle karşılaştırman gerekirse Python'da hmac.compare_digest kullan.

Kullanıcı adı yoksa ne olduğuna da bak. Sistem hemen dönerse yanıt süresi hangi hesabın var olduğunu ele verir. Bu durumda sahte bir özet üzerinde doğrulama çalıştırıp süreyi eşitlersin.

Etkinlik 6 / 8

Girişte parola doğrulamanın doğru adım sırasını kur.

Parçalara tıklayarak komutu soldan sağa kur.

$

Parola politikası, kara liste ve göç

Özetleme işin yarısıdır, öbür yarısı zayıf parolayı hiç kabul etmemektir. NIST SP 800-63B'nin Temmuz 2025'te yayımlanan 4. revizyonu kuralları sadeleştirdi. Parola tek faktörse en az 15, çok faktörlü doğrulamanın parçasıysa en az 8 karakter olmalıdır.

Sistem en az 64 karakterlik parolayı kabul etmelidir. Harf, rakam, özel karakter karışımı gibi bileşim kuralları ve periyodik zorunlu değişim artık dayatılmaz.

Değişim yalnız ele geçirilme belirtisi varsa istenir. Buna karşılık yeni parola, sızıntılarda görülmüş, yaygın ya da bağlama özgü parolalardan oluşan bir kara listeyle karşılaştırılır. Başarısız denemeler için hız sınırı da zorunludur.

Kara listeyi kurmanın pratik yolu, sızmış parolaları k-anonimlik ile sorgulayan bir aralık servisidir. Have I Been Pwned'in Pwned Passwords servisi böyle çalışır; herkese açıktır ve anahtar istemez. Parolayı ya da tam özetini göndermezsin.

Parolanın SHA-1 özetini yerelde hesaplar, yalnız ilk 5 onaltılık karakteri yollarsın. Servis bu önekle başlayan bütün özetlerin kalan 35 karakterini ve sızıntılarda kaç kez görüldüklerini döner. Eşleşmeyi kendi tarafında ararsın.

Altay Kargo, kayıt ekranı dış servise bağlı kalmasın diye listenin indirilebilir kopyasını kendi ağında aynı arayüzle sunar. Aşağıdaki sorgu o iç kopyaya gider. Aynı sorguyu herkese açık servise de yollayabilirsin; adresi kaynaklardaki API belgesinde yazar.

$ echo -n "password" | shasum -a 1
5baa61e4c9b93f3f0682250b6cf8331b7ee68fd8  -

$ curl -s https://parola-kontrol.altaykargo.example/range/5BAA6 | grep 1E4C9B93F3F0682250B6CF8331B7EE68FD8
1E4C9B93F3F0682250B6CF8331B7EE68FD8:52372427
k-anonimlik aralık sorgusu: sunucuya yalnız beş karakterlik önek gider.

İlk komut SHA-1 özetini üretir. İlk beş karakter (5BAA6) sorguya giden tek bilgidir. Yanıt iki bine yakın satırdır ve her satır SONEK:SAYI biçimindedir. grep kendi özetinin kalan 35 karakterini arar.

Eşleşen satır, password parolasının sızıntılarda 52 milyondan fazla kez görüldüğünü söyler. Servis hangi parolayı sorduğunu bilmez, çünkü aynı öneki binlerce özet paylaşır. Kayıt ve parola değişikliği ekranında sayı sıfırdan büyükse parolayı reddedersin. SHA-1 burada saklama için değil, yalnız sorgu anahtarı olarak çalışır.

Elinde eski MD5 ya da SHA-1 özetleri varsa ne yaparsın? Düz parolalar sende olmadığı için tabloyu tek hamlede yeniden özetleyemezsin. OWASP iki adımlı bir yol önerir.

İlk adımda eski özeti yeni algoritmaya girdi yaparsın. Kayıt argon2id(sha1(parola)) biçimine döner ve bir işaretle katmanlı olduğu belirtilir. Bu adım bütün tabloya hemen uygulanır, hızlı özet artık açıkta durmaz.

İkinci adımda kullanıcı giriş yaptıkça elindeki düz parolayla temiz bir Argon2id özeti üretir, katmanlı kaydı silersin. Uzun süre giriş yapmayan hesaplar için bir tarihten sonra parola sıfırlamayı zorunlu tutarsın.

Son olarak sık yapılan hataları topla. bcrypt'e 72 bayttan uzun parola vermek çoğu uygulamada sessiz bir kesime yol açar; Türkçe harfler UTF-8'de iki bayt tuttuğu için sınıra erken ulaşırsın. Parola sıfırlama jetonunu düz metin saklamak, tabloyu okuyan herkese hesap devralma imkânı verir; jetonu da özetle.

Pepper'ı aynı veritabanında tutmak onu işlevsiz bırakır. Uzunluk ve kara liste denetimini yalnız tarayıcıda yapmak da yetmez; saldırgan isteği doğrudan sunucuya yollar, denetim sunucuda çalışmalıdır.

Derinleş:bcrypt'in 72 bayt sınırı ve ön özetleme

bcrypt, Blowfish şifresinin anahtar kurulumuna dayanır ve bu anahtar en çok 72 bayt olabilir. Klasik uygulamalar 72 bayttan sonrasını sessizce yok sayar; ilk 72 baytı aynı olan iki parola aynı özeti üretir. Python'un bcrypt paketi ise 5.0 sürümünden beri bu durumda hata verir.

Uzun parola ifadelerini desteklemek isteyen bazı ekipler parolayı önce SHA-256 gibi hızlı bir fonksiyonla özetleyip sonucu bcrypt'e verir. OWASP bu ön özetlemeye iki uyarı yapar. Birincisi, ham özet çıktısı sıfır baytı içerebilir ve bazı bcrypt uygulamaları girdiyi o noktada keser. İkincisi password shucking adlı saldırıdır.

Saldırgan başka sızıntılardan topladığı hızlı özetleri doğrudan bcrypt'in girdisi olarak dener. Böylece parolayı tahmin etmeden, elindeki özet listesini aday gibi kullanır. Aynı sorun katmanlı göçte de vardır; bu yüzden katmanlı kayıt kalıcı bir çözüm değil, geçiş durumudur. Yeni bir sistemde bu tuzakları hiç taşımayan Argon2id en temiz seçimdir.

Etkinlik 7 / 8

Altay Kargo'nun eski kullanıcıları hâlâ tuzsuz SHA-1 özetiyle saklanıyor. Sisteme yeni Argon2id geçilirken en doğru yaklaşım hangisidir?

Etkinlik 8 / 8

API anahtarını veritabanında saklarken de parola gibi davran: anahtarı düz metin değil, tuzlu bir ____ olarak sakla.

Bu derste bir hata mı gördün? Bildir