Bölüm 12
Authentication (Kimlik Doğrulama)
Bölüm 1 (type juggling, hashequals, güven sınırı). İleri referanslar: Bölüm 13 (parola hash'leme/kriptografi), Bölüm 16 (oturum).
Kimlik doğrulamayı bir "giriş formu" olarak değil, kimliği kanıtlama süreci olarak kavrayacak; kimlik doğrulama (authN) ile yetkilendirme (authZ) arasındaki farkı, sürecin en sık kırıldığı noktaları (bozuk kimlik bilgisi karşılaştırması, kullanıcı numaralandırma, kaba kuvvet, parola sıfırlama) ve MFA'nın rolünü göreceksiniz.
1. Giriş
Kimlik doğrulama, güvenlik mimarisinin temel taşıdır: sistemin "sen kimsin?" sorusuna verdiği yanıttır. Bu yanıt yanlış olduğunda — bir saldırgan başkasının kimliğine büründüğünde — diğer tüm savunmalar anlamsızlaşır. Yetkilendirme (Bölüm 14), erişim kontrolü, denetim izleri: hepsi doğru bir kimlik doğrulaması varsayar. Bu yüzden STRIDE'da (Bölüm 2) "Spoofing" (kimlik taklidi) kategorisi doğrudan kimlik doğrulamanın karşıtıdır.
Kimlik doğrulamanın en tehlikeli yanı, kusurlarının çoğu zaman "sessiz" olmasıdır. SQL Injection bir hata mesajı üretir, XSS bir script çalıştırır — görünür. Ama zayıf bir kimlik doğrulama, hiçbir alarm çalmadan aylarca istismar edilebilir; saldırgan meşru bir kullanıcı gibi görünür. Bu yüzden kimlik doğrulama kusurları hem yüksek etkili hem de tespiti zor olur.
Bu bölüm, kimlik doğrulama sürecine odaklanır. Parola nasıl saklanır sorusu Bölüm 13'ün (kriptografi), oturum nasıl yönetilir sorusu Bölüm 16'nın konusudur. Burada süreç zincirini inceleyeceğiz: kimliği belirle → kimlik bilgisini doğrula → oturumu kur — ve bu zincirin her halkasının nasıl kırıldığını.
2. Temel Teori
AuthN vs AuthZ — kritik ayrım. İki kavram sık karıştırılır: - Authentication (authN): "Sen kimsin?" Kimliği kanıtlama. (Bu bölüm.) - Authorization (authZ): "Neye iznin var?" Kanıtlanmış kimliğin yetkilerini belirleme. (Bölüm 14.)
Bir kullanıcı doğru kimlik doğrulanmış ama yanlış yetkilendirilmiş olabilir (IDOR, Bölüm 15) — ya da tam tersi. İkisini ayrı katmanlar olarak düşünmek, tasarımın temelidir.
Kimlik doğrulama faktörleri. Kimlik üç tür kanıtla doğrulanır: - Bildiğin bir şey (parola, PIN) - Sahip olduğun bir şey (telefon, donanım anahtarı, TOTP üreteci) - Olduğun bir şey (parmak izi, yüz)
Tek faktör (genellikle parola) kırılgandır; çok faktörlü kimlik doğrulama (MFA) en az iki farklı türü birleştirir ve tek bir faktörün ele geçirilmesini yetersiz kılar.
Süreç ve kırılma noktaları. Kimlik doğrulama bir zincirdir; her halka bir açık sınıfına karşılık gelir:
| Adım | Kırılma noktası | Açık |
|---|---|---|
| Kimliği belirle | Farklı yanıt/zamanlama | Kullanıcı numaralandırma |
| Kimlik bilgisini doğrula | Gevşek/güvensiz karşılaştırma | Auth bypass (type juggling) |
| Deneme sayısını sınırla | Sınırsız deneme | Brute force / credential stuffing |
| Oturumu kur | Zayıf token/sabitleme | Session hijacking (Bölüm 16) |
| Kurtarma (reset) | Tahmin edilebilir token | Hesap devralma |
PHP'ye özgü kök neden — gevşek karşılaştırma. Bölüm 1'de gördüğümüz type juggling, en sık tam olarak burada — kimlik bilgisi doğrulamasında — felakete dönüşür. $hash == $input gibi bir karşılaştırma, "magic hash" değerleriyle atlatılabilir; çünkü 0e... biçimindeki iki hash PHP tarafından sayısal sıfır sayılıp eşit görülür. Bu, parolayı bilmeden girişe imkân verir (Bölüm 11'deki MantisBT vakası).
3. Mimarisel Bakış
Kullanıcı → [Giriş formu] → ╳ güven sınırı ╳
↓
1) Kimliği belirle (username/email)
↓ ← numaralandırma riski: "kullanıcı yok" vs "parola yanlış"
2) Kimlik bilgisini doğrula
↓ ← password_verify (Böl. 13) / hash_equals — ASLA ==
↓ ← kaba kuvvet: hız sınırı + hesap kilidi
3) MFA (varsa) — ikinci faktör
↓
4) Oturumu kur (Böl. 16)
↓ ← session_regenerate_id (fixation önlemi)
Kimlik doğrulanmış oturum
Paralel akış — Parola sıfırlama:
İstek → rastgele token üret (random_bytes) → HASH'lenerek DB'de sakla
→ kayıtlı e-postaya gönder (Host başlığına GÜVENME)
→ token doğrula (hash_equals) + süre + tek kullanım → yeni parola
Her okun yanındaki not, o adımın kırılma noktasıdır. Güvenli kimlik doğrulama, bu zincirin her halkasını ayrı ayrı sağlamlaştırmayı gerektirir.
4. Güvensiz Kod
Gerçekçi bir giriş ve parola sıfırlama akışı:
<?php
// ⚠️ GÜVENSİZ — çok katmanlı kimlik doğrulama hataları
declare(strict_types=1);
// --- Giriş ---
$user = $pdo->prepare('SELECT id, pass_md5 FROM users WHERE email = ?');
$user->execute([$_POST['email']]);
$row = $user->fetch();
if (!$row) {
exit('Böyle bir kullanıcı yok'); // numaralandırma sızıntısı
}
if ($row['pass_md5'] == md5($_POST['password'])) { // GEVŞEK karşılaştırma + MD5
$_SESSION['uid'] = $row['id']; // fixation: id yenilenmiyor
exit('Giriş başarılı');
}
exit('Parola yanlış'); // farklı mesaj → numaralandırma
// --- Parola sıfırlama (başka dosyada) ---
$token = md5($row['email'] . time()); // tahmin edilebilir token
$link = 'https://' . $_SERVER['HTTP_HOST'] . '/reset?t=' . $token; // Host güveni
mail($row['email'], 'Sıfırlama', $link);
Bu kod, sınırsız deneme (kaba kuvvet önlemi yok) sorununu da örtük olarak barındırır.
5. Açığın Analizi
$row['pass_md5'] == md5($_POST['password']) — İki hata bir arada. (1) Gevşek karşılaştırma (==): Depolanan hash 0e... biçimindeyse (magic hash), saldırgan hash'i yine 0e... çıkan bir parola girerek doğrulamayı geçer — parolayı bilmeden (Bölüm 1, 11). (2) MD5: Parola için kriptografik olarak kırık, tuzsuz, hızlı bir hash (Bölüm 13); rainbow table ve GPU brute force'a açık.
exit('Böyle bir kullanıcı yok') vs exit('Parola yanlış') — Kullanıcı numaralandırma. İki farklı mesaj, saldırgana "bu e-posta kayıtlı mı?" sorusunu yanıtlar. Saldırgan geçerli kullanıcı listesi çıkarır; bu, hedefli kaba kuvvet ve credential stuffing için ilk adımdır. Aynı sızıntı zamanlama farkıyla da olur: var olan kullanıcıda hash doğrulaması çalışır (yavaş), olmayanda hemen döner (hızlı).
$_SESSION['uid'] = $row['id'] (id yenilenmeden) — Session fixation (Bölüm 16). Oturum kimliği girişten sonra yenilenmediğinden, saldırgan önceden belirlediği bir oturum kimliğini kurbana kabul ettirip giriş sonrası devralabilir.
md5($row['email'] . time()) (reset token) — Tahmin edilebilir token. email bilinir, time() saniye hassasiyetinde tahmin edilebilir; token entropi taşımaz. Saldırgan, bir kullanıcının sıfırlama token'ını tahmin edip hesabı devralır. Ayrıca token'ın süresi ve tek-kullanımlılığı yok.
$_SERVER['HTTP_HOST'] (reset link) — Host header poisoning (Bölüm 1). Host başlığı istemci kontrollüdür; saldırgan onu kendi alan adıyla değiştirirse, sıfırlama linki saldırganın sunucusuna işaret eder ve kurban linke tıkladığında token saldırgana sızar.
Kök sorun: kimlik doğrulama zincirinin her halkası ayrı ayrı zayıf. Tek bir düzeltme yetmez; katman katman sağlamlaştırma gerekir.
6. Hacker Bakış Açısı
Saldırgan kimlik doğrulamayı nasıl hedefler?
Önce numaralandırır. Giriş, kayıt ve sıfırlama uç noktalarına geçerli/geçersiz kullanıcılarla istek atıp yanıt farkını arar: farklı mesaj, farklı durum kodu, farklı yönlendirme veya farklı süre. Geçerli kullanıcı listesi, sonraki tüm saldırıların temelidir.
Kimlik bilgisi karşılaştırmasını yoklar. PHP uygulamalarında ilk kontrol ettiği şeylerden biri sürüm ve == kullanımıdır. Kimlik doğrulama yakınında gevşek karşılaştırma varsa, magic hash ile atlatmayı dener (Bölüm 1). Bu, "iki karakterlik fark"ın (== vs ===) tam admin erişimine dönüştüğü yerdir.
Kaba kuvvet ve credential stuffing dener. Hız sınırı ve hesap kilidi yoksa, otomatik araçlarla parola dener. Daha etkilisi credential stuffing'tir: başka ihlallerden sızmış milyonlarca e-posta/parola çiftini dener; kullanıcılar parola tekrar kullandığı için başarı oranı yüksektir. Numaralandırmayla elde edilen geçerli kullanıcı listesi bunu hedefli kılar.
Sıfırlama akışını istismar eder. Token'ın nasıl üretildiğini (tahmin edilebilir mi?), süresinin/tek-kullanımının olup olmadığını ve Host başlığının linke yansıyıp yansımadığını test eder. Parola sıfırlama, çoğu uygulamanın en zayıf kimlik doğrulama halkasıdır çünkü "giriş kadar dikkat" gösterilmez.
MFA'yı atlatmayı dener. MFA varsa, onu atlayan yolları arar: MFA'sız eski bir uç nokta, MFA doğrulamasını atlayan bir mantık hatası, ya da MFA kodunun kendisine kaba kuvvet (hız sınırı yoksa).
Savunmacı dersi: Saldırgan zinciri en zayıf halkadan kırar. Giriş formu sağlam olsa da, numaralandırma + zayıf sıfırlama + MFA eksikliği bir araya gelince hesap devralma kaçınılmazlaşır.
7. Exploit Mantığı
Bu bölüm çalıştırılabilir saldırı içermez. Kimlik doğrulama kusurlarının neden bu kadar etkili olduğu kavramsaldır:
- Kimlik taklidi = tüm yetkilerin devri. Bir saldırgan kimlik doğrulamayı geçtiğinde, o kullanıcının tüm yetkilerini kazanır. Admin hesabıysa sonuç tam sistem devri; sıradan kullanıcıysa onun verisi ve işlemleri. Etki, ele geçirilen hesabın yetkisi kadardır.
- Sessizlik. Kimlik taklidi meşru bir giriş gibi göründüğü için, saldırgan tespit edilmeden uzun süre kalabilir. Bu, kimlik doğrulama kusurlarını özellikle tehlikeli yapar.
- Zincirleme numaralandırma. Numaralandırma tek başına düşük şiddetlidir, ama hedefli credential stuffing'i ve sıfırlama saldırılarını mümkün kılarak zincirin çarpanı olur (Bölüm 2).
- Sıfırlama = arka kapı. Zayıf bir parola sıfırlama, en güçlü parola politikasını bile anlamsız kılar; saldırgan parolayı kırmak yerine sıfırlar.
Araştırmacının çerçevesi: (a) geçerli kullanıcı belirlenebiliyor mu, (b) kimlik bilgisi karşılaştırması/sıfırlama zayıf mı, (c) deneme/ikinci faktör sınırı var mı. Savunma, her halkayı ayrı sağlamlaştırarak zinciri bütün olarak korur.
8. Güvenli Kod
Zincirin her halkasını sağlamlaştıran sürüm:
<?php
// ✅ GÜVENLİ — katmanlı kimlik doğrulama
declare(strict_types=1);
// --- Giriş ---
$email = filter_var($_POST['email'] ?? '', FILTER_VALIDATE_EMAIL);
$pass = (string)($_POST['password'] ?? '');
// Hız sınırı (basit örnek; üretimde merkezî bir mekanizma kullanın)
if (rateLimiter()->tooManyAttempts($email, $_SERVER['REMOTE_ADDR'])) {
http_response_code(429);
exit('Çok fazla deneme. Lütfen bekleyin.');
}
$stmt = $pdo->prepare('SELECT id, pass_hash FROM users WHERE email = ?');
$stmt->execute([$email]);
$row = $stmt->fetch();
// Numaralandırmayı önle: kullanıcı olmasa bile SABİT SÜRE harca (dummy verify)
$hash = $row['pass_hash'] ?? '$2y$12$............................................';
$valid = password_verify($pass, $hash) && $row !== false; // Böl. 13
rateLimiter()->hit($email, $_SERVER['REMOTE_ADDR']);
if (!$valid) {
// TEK ve GENEL mesaj — hangi alanın yanlış olduğunu sızdırma
http_response_code(401);
exit('E-posta veya parola hatalı.');
}
// Fixation önlemi: girişten sonra oturum kimliğini yenile (Böl. 16)
session_regenerate_id(true);
$_SESSION['uid'] = $row['id'];
// Hash eskiyse (algoritma/maliyet) sessizce yükselt (Böl. 13)
if (password_needs_rehash($hash, PASSWORD_DEFAULT, ['cost' => 12])) {
$new = password_hash($pass, PASSWORD_DEFAULT, ['cost' => 12]);
$pdo->prepare('UPDATE users SET pass_hash = ? WHERE id = ?')->execute([$new, $row['id']]);
}
Güvenli parola sıfırlama:
<?php
// ✅ GÜVENLİ — parola sıfırlama
declare(strict_types=1);
// 1) Kriptografik rastgele token; DB'de yalnızca HASH'i saklanır
$token = bin2hex(random_bytes(32)); // 256-bit entropi
$tokenHash = hash('sha256', $token);
$pdo->prepare('INSERT INTO password_resets (user_id, token_hash, expires_at, used)
VALUES (?, ?, ?, 0)')
->execute([$userId, $tokenHash, time() + 3600]); // 1 saat geçerli
// 2) Host başlığına GÜVENME — yapılandırmadan sabit taban URL kullan
$base = config('app.url'); // örn. https://app.example.com
$link = $base . '/reset?t=' . $token; // ham token yalnızca e-postada
mail($email, 'Parola sıfırlama', $link);
// 3) Doğrulama (reset sayfası)
$provided = hash('sha256', (string)($_GET['t'] ?? ''));
$rec = $pdo->prepare('SELECT * FROM password_resets WHERE token_hash = ?');
$rec->execute([$provided]);
$r = $rec->fetch();
if (!$r || $r['used'] || $r['expires_at'] < time()
|| !hash_equals($r['token_hash'], $provided)) { // sabit-süreli karşılaştırma
http_response_code(400);
exit('Geçersiz veya süresi dolmuş bağlantı.');
}
// tek kullanım: doğrulama sonrası 'used = 1'
Öne çıkan modern kalıplar:
- password_verify / password_hash (Bölüm 13) — parola doğrulaması; asla ==/MD5.
- hash_equals — token/hash karşılaştırmalarında sabit-süreli, tipe duyarlı (Bölüm 1).
- Genel hata mesajı + sabit süre — kullanıcı numaralandırmayı (mesaj ve zamanlama) engeller. Kullanıcı yoksa bile bir dummy password_verify çalıştırarak süreyi eşitle.
- Hız sınırı + hesap kilidi — kaba kuvvet/credential stuffing'e karşı.
- Kriptografik reset token — random_bytes, DB'de hash'lenmiş, süreli, tek-kullanımlık.
- Host başlığına güvenme — link tabanını yapılandırmadan al (Bölüm 1 host header).
- session_regenerate_id(true) — fixation önlemi (Bölüm 16).
- MFA — mümkün olan her yerde ikinci faktör (TOTP/WebAuthn).
9. Patch Analizi
Neden işe yarar? Her düzeltme zincirin bir halkasını kapatır: password_verify kriptografik doğru doğrulama sağlar ve type juggling'i imkânsız kılar (dize karşılaştırması == yok); genel mesaj + sabit süre numaralandırmayı keser; hız sınırı kaba kuvveti durdurur; kriptografik token sıfırlamayı güvenli kılar; session_regenerate_id fixation'ı kapatır. Tek bir savunma değil, katmanlı savunma (Bölüm 1) uygulanır.
Numaralandırma karşıtı sabit-süre — inceleme: Saldırgan zamanlama farkıyla kullanıcı varlığını anlayabildiği için, kullanıcı yokken de bir dummy password_verify çalıştırmak süreyi eşitler. Bu, "sızıntı yalnızca mesajda değil, sürede de olur" içgörüsünün pratiğidir.
Alternatiflerin karşılaştırması:
| Konu | Zayıf | Güçlü |
|---|---|---|
| Parola doğrulama | == md5() |
password_verify (bcrypt/argon2) |
| Token karşılaştırma | == |
hash_equals |
| Hata mesajı | Ayrı (kullanıcı/parola) | Tek genel mesaj + sabit süre |
| Kaba kuvvet | Sınırsız | Hız sınırı + kilit + MFA |
| Reset token | md5(email.time()) |
random_bytes + hash + süre + tek kullanım |
| Link tabanı | HTTP_HOST |
Yapılandırma sabiti |
Performans: password_verify bilinçli olarak yavaştır (Bölüm 13) — bu bir özelliktir, kaba kuvveti pahalılaştırır. Dummy verify küçük bir maliyet ekler ama numaralandırmayı kapatır; kabul edilebilir. Hız sınırı, meşru kullanıcıyı etkilemeyecek eşiklerle ayarlanır.
10. Gerçek Hayat Senaryosu
Kurgu — bir çevrimiçi bankacılık portalı. Giriş formu güçlü: bcrypt, ===, MFA. Ama parola sıfırlama akışı yıllar önce yazılmış ve md5(userId . time()) token kullanıyor; ayrıca link Host başlığından kuruluyor. Saldırgan MFA'lı güçlü girişi hiç denemez; bunun yerine sıfırlama akışını hedefler. Numaralandırmayla geçerli müşteri e-postalarını çıkarır, Host başlığını kendi alan adıyla değiştirerek sıfırlama linkini kendine yönlendirir ve time() penceresini daraltarak token'ı tahmin eder. Sonuç: MFA'yı hiç görmeden hesap devralma. Dersler: (1) kimlik doğrulama en zayıf halkasından kırılır — güçlü giriş, zayıf sıfırlamayı kurtarmaz; (2) Host başlığı güvenilmez girdidir; (3) sıfırlama akışı giriş kadar titiz tasarlanmalıdır.
11. Gerçek CVE Analizi — Type Juggling Auth Bypass (MantisBT, GHSA-4v8w-gg5j-ph37; ve CVE-2023-53894)
MantisBT resmî GitHub Security Advisory'si, MITRE/NVD ve satıcı notlarıyla doğrulanmıştır. Silahlaştırılmış payload verilmez.
Özet. Yaygın kullanılan açık kaynak PHP hata izleme sistemi MantisBT'de, kimlik doğrulama kodundaki gevşek karşılaştırma nedeniyle bir kimlik doğrulama atlatma açığı bulundu. MD5 giriş yöntemi yapılandırılmış örneklerde, parola hash'i sıfıra eşitlenen (magic hash) hesaplar, parolası bilinmeden ele geçirilebiliyordu. Aynı sınıfın güncel bir örneği, phpfm 1.7.9'daki CVE-2023-53894'tür (kritik, tip karşılaştırmasıyla giriş atlatma → kötü niyetli PHP dosyası yükleme).
Teknik neden — Bölüm 1'in gerçek dünyadaki bedeli. MantisBT'nin kimlik doğrulama kodu, saklanan hash ile hesaplanan hash'i sıkı (===) yerine gevşek (==) karşılaştırıyordu. PHP, ^0+[Ee][0-9]+$ desenine uyan iki dizeyi (ör. 0e5796...) bilimsel gösterimli sayı — sıfır — olarak yorumladığından, hash'i bu desene uyan bir hesap için, hash'i yine sıfıra eşitlenen herhangi başka bir parola doğrulamayı geçiyordu. Kurbanın kullanıcı adını bilen bir saldırgan, örneğin hash'i 0e... çıkan basit bir dizeyle (advisory comito5 örneğini verir) giriş yapabiliyordu.
Kritik incelik: bu, egzotik bir kripto zafiyeti değil, iki karakterlik bir fark (== yerine ===). Aynı kök neden Bölüm 1'de anlatıldı; buradaki ders, o "teorik" davranışın gerçek, adı konmuş, yaygın uygulamalarda tam kimlik doğrulama atlatmasına yol açtığıdır. Sızma testlerinde PHP uygulamalarının ilk kontrol edilen noktalarından biri budur.
Etki. Kullanıcı adı bilinen (numaralandırmayla kolayca elde edilebilen) bir hesabın, parola bilinmeden ele geçirilmesi. phpfm örneğinde (CVE-2023-53894) bu, dosya yükleme yetkisiyle birleşince RCE'ye tırmandı.
Satıcı düzeltmesi. Gevşek karşılaştırma sıkı karşılaştırmayla (===) ve/veya hash_equals ile değiştirildi; ayrıca modern uygulamalar MD5 giriş yöntemini terk edip password_hash/password_verify'a (Bölüm 13) geçti.
Çıkarılacak dersler:
1. Güvenlik kararı veren her karşılaştırma sıkı olmalı (===/hash_equals). ==, kimlik doğrulama/yetki yakınında bir kusurdur (Bölüm 1).
2. MD5 giriş yöntemi başlı başına bir sorundur (Bölüm 13); modern parola API'sine geçin.
3. Basit görünen kusurlar en yaygın olanlardır. "İki karakter" düzeyindeki bir hata, tam kimlik doğrulama atlatmasına yol açabilir; kod incelemede kimlik doğrulama yakınındaki == özel olarak aranmalıdır.
12. Detection
Kod incelemede: Kimlik doğrulama/token yakınındaki gevşek karşılaştırmayı ve zayıf token üretimini arayın:
grep -rnE '==[^=]' src/auth/ src/login* | grep -iE 'pass|hash|token|secret' # gevşek karşılaştırma
grep -rn 'md5(\|sha1(' src/ # parola/token için zayıf hash
grep -rn 'HTTP_HOST' src/ # host header güveni (reset link)
grep -rnE 'mail\(|reset' src/ | grep -i token # sıfırlama token üretimi
Her bulguda: karşılaştırma ===/hash_equals mı? Token random_bytes mı? Mesajlar genel mi?
SAST: Gevşek karşılaştırma (CWE-697), zayıf hash (CWE-327/916) ve tahmin edilebilir token (CWE-330) için olgun kurallar. Kimlik doğrulama akışlarını özel olarak işaretler.
DAST: Kullanıcı numaralandırmayı (yanıt/zamanlama farkı), hız sınırı eksikliğini ve sıfırlama token öngörülebilirliğini test eder.
Loglar/SIEM: Başarısız girişlerdeki ani artış (kaba kuvvet), aynı IP'den çok sayıda farklı kullanıcı denemesi (credential stuffing / numaralandırma), tek kullanıcıya çok IP'den denemeler, ve olağandışı saatlerde başarılı girişler. Kimlik doğrulama olayları için korelasyon kuralları en değerli SIEM içeriklerindendir. Başarılı bir giriş başarısızlar patlamasının hemen ardından geliyorsa, kaba kuvvet başarısı işareti olabilir.
13. Prevention
- Sıkı karşılaştırma her yerde:
===/hash_equals;==kimlik doğrulama/yetkide yasak. - Modern parola API'si:
password_hash/password_verify(Bölüm 13); MD5/SHA1 giriş yöntemi yok. - Numaralandırmayı önle: Tek genel mesaj + sabit süre (dummy verify).
- Kaba kuvvet savunması: Hız sınırı + hesap kilidi + CAPTCHA (eşikte) + MFA.
- Güçlü sıfırlama:
random_bytestoken, hash'lenmiş saklama, süre + tek kullanım,Hostgüveni yok. - MFA'yı varsayılan yap: TOTP/WebAuthn; MFA'sız yan yollar kapatılır.
- Güvenli oturum devri: Girişten sonra
session_regenerate_id(true)(Bölüm 16). - Threat modeling: Kimlik akışlarını STRIDE "Spoofing" merceğiyle incele (Bölüm 2).
14. Mitigation
- Acil: Kimlik doğrulama karşılaştırmalarını
===/hash_equals'a çevir; hız sınırı devreye al; zayıf sıfırlama akışını geçici kapat. - Geçici: Loglardan atlatma/ele geçirme kapsamını belirle; şüpheli hesapların oturumlarını iptal et, parolalarını sıfırlat; magic-hash'e uyan hesapları tespit edip rehash zorla.
- Kalıcı: Modern parola API'sine geç; MFA'yı yay; sıfırlama akışını yeniden yaz; testler + SAST kuralları + SIEM korelasyonları ekle.
15. Checklist
- [ ] Parola/token karşılaştırmaları
===/hash_equalsmı (==yok)? - [ ] Parolalar
password_hash/password_verifyile mi (MD5/SHA1 yok)? - [ ] Giriş/kayıt/sıfırlama yanıtları kullanıcı numaralandırmaya kapalı mı (mesaj + zamanlama)?
- [ ] Kaba kuvvet/credential stuffing'e karşı hız sınırı + kilit var mı?
- [ ] MFA sunuluyor ve mümkün olan yerde zorunlu mu?
- [ ] Sıfırlama token'ı
random_bytes+ hash'li saklama + süre + tek kullanım mı? - [ ] Sıfırlama linki
Hostbaşlığından değil, yapılandırmadan mı kuruluyor? - [ ] Girişten sonra
session_regenerate_id(true)çağrılıyor mu (Bölüm 16)? - [ ] Kimlik doğrulama olayları loglanıp SIEM'de korele ediliyor mu?
16. Laboratuvar
Lab 12.1 — Type juggling atlatma. İzole ortamda $hash == md5($input) ile bir giriş kur; depolanan hash'i bir magic hash (0e...) yap ve hash'i yine 0e... çıkan bir girdiyle doğrulamayı geç. Sonra password_verify/hash_equals'a geçip atlatmanın neden imkânsızlaştığını göster.
Lab 12.2 — Numaralandırma. İki farklı mesaj döndüren bir giriş yaz; geçerli/geçersiz kullanıcıda yanıtın (ve sürenin) farkını ölç. Tek genel mesaj + dummy verify ile farkı kapat.
Lab 12.3 — Güvenli sıfırlama token. md5(email.time()) token ile random_bytes token'ı karşılaştır; entropi ve tahmin edilebilirlik farkını yaz. Süre + tek kullanım ekle.
Lab 12.4 — Host header. Reset linkini HTTP_HOST'tan kuran bir akış yaz; Host başlığını değiştirerek linkin nasıl saldırgana yöneldiğini gözlemle. Yapılandırma sabitiyle düzelt.
17. Quiz
- AuthN ile AuthZ arasındaki fark nedir? Bir kullanıcı doğru authN ama yanlış authZ ile hangi açığa maruz kalır?
- Üç kimlik doğrulama faktörü nedir? MFA neden tek faktörden güçlüdür?
- Kullanıcı numaralandırma nedir ve mesaj dışında hangi kanaldan sızar?
- Type juggling kimlik doğrulama atlatması nasıl çalışır?
==yerine ne kullanılmalı? - Numaralandırmayı önlemek için kullanıcı yokken neden "dummy" bir doğrulama çalıştırılır?
- Credential stuffing nedir ve numaralandırmayla nasıl birleşir?
- Zayıf bir parola sıfırlama akışı, güçlü bir parola politikasını neden anlamsız kılar?
Hostbaşlığına dayalı sıfırlama linki neden tehlikelidir? (Bölüm 1'e atıfla.)- Güvenli bir reset token'ın dört özelliği nedir?
- MantisBT vakası, "iki karakterlik" bir hatanın neden kritik olabileceğini nasıl gösterir?
session_regenerate_id(true)girişte neden çağrılır?- SIEM'de kaba kuvvet başarısını gösteren korelasyon kalıbı nedir?
18. Kaynakça
- OWASP, Authentication Cheat Sheet; Forgot Password Cheat Sheet; Credential Stuffing Prevention Cheat Sheet.
- OWASP, Top 10:2021 — A07 Identification and Authentication Failures.
- MITRE, CWE-287: Improper Authentication; CWE-697: Incorrect Comparison; CWE-620: Unverified Password Change; CWE-640: Weak Password Recovery.
- MantisBT, GHSA-4v8w-gg5j-ph37 (type juggling auth bypass) resmî advisory; MITRE/NVD, CVE-2023-53894 (phpfm).
- PHP Manual,
password_verify,password_needs_rehash,hash_equals,random_bytes,session_regenerate_idreferansları. - NIST SP 800-63B, Digital Identity Guidelines — Authentication and Lifecycle Management.