PHP Şifreleme ve Güvenlik: password_hash() ve password_verify() Kullanımı

Parola güvenliği modern web uygulamalarında temel bir gereksinimdir. PHP, doğru kullanıldığında güçlü ve güncel şifreleme araçları sunar. Bu makalede password_hash() ve password_verify() fonksiyonlarının nasıl çalıştığını, neden her çalıştırmada farklı hash üretildiğini, doğru saklama ve yeniden hash stratejilerini ve yaygın hataları ele alacağız.

Giriş — Neden password_hash ve password_verify?

Eskiden geliştiriciler MD5 veya SHA1 gibi tek dönüşümlü fonksiyonları doğrudan kullanıyordu; bu yöntemler artık yetersiz ve tehlikelidir. PHP'nin password_hash() fonksiyonu, otomatik salt üretimi ve adaptif (maliyet ayarlı) algoritmalar kullanarak güvenli, tek yönlü parola hash'leri üretir. Doğrulama için ise password_verify() fonksiyonu güvenli ve zamanlama saldırılarına karşı duyarlı olmayan bir karşılaştırma sağlar.

Nasıl çalışır? Teknik özet

password_hash()

password_hash() şu özelliklere sahiptir:

  • Güçlü, tek yönlü bir hash üretir.
  • Salt otomatik olarak üretilir ve hash içinde saklanır; geliştiricinin manuel salt yönetmesine gerek yoktur.
  • PASSWORD_DEFAULT gibi sabitler kullanıldığında PHP, önerilen adaptif algoritmayı (ör. bcrypt) ve varsayılan maliyeti uygular.
  • Çıktı her çalıştırmada farklı olabilir; bu, her hash için farklı salt kullanıldığından beklenen davranıştır.

password_verify()

password_verify(), kullanıcıdan gelen düz metin parolayı, veritabanında saklanan hash ile karşılaştırır. Fonksiyon hash içindeki salt ve algoritma bilgilerini kullanır ve güvenli, sabit zamanlı bir karşılaştırma uygular:

  • Fonksiyonu kullanmak, manuel karşılaştırma ve zamanlama saldırılarına açık kod yazma riskini ortadan kaldırır.
  • Doğrulama başarılıysa true, başarısızsa false döner.

Hızlı örnek

Aşağıdaki örnek temel kullanım örneğini gösterir:

<?php
// Kayıt sırasında
$plainPassword = 'S3cureP@ssw0rd';
$hash = password_hash($plainPassword, PASSWORD_DEFAULT);
// $hash veritabanına kaydedilir (ör: users.password)

// Giriş doğrulaması sırasında
$entered = 'S3cureP@ssw0rd';
if (password_verify($entered, $hash)) {
    // Başarılı doğrulama
} else {
    // Hatalı parola
}
?>

Not: Yukarıdaki örnekte tek yapmanız gereken password_hash ile hash üretip veritabanına kaydetmek, girişte ise password_verify ile kontrol etmektir.

Neden aynı parola için farklı hash'ler üretilir?

Her call'da yeni bir salt üretilir; salt hash içinde tutulur ve bu sayede aynı parolanın farklı hash'leri oluşur. Bu, sözlük/saldırı tablolarının etkisini azaltır ve güvenliği artırır. Bu davranış normal ve arzu edilen bir durumdur.

En iyi uygulamalar ve öneriler

  • Her zaman password_hash ve password_verify kullanın: Salt yönetimi ve sabit zamanlı karşılaştırma gibi karmaşık ve hata-prone konuları PHP sizin için halleder.
  • PASSWORD_DEFAULT kullanın: PHP'nin önerdiği varsayılan adaptif algoritmayı kullanmak, zamanla daha güçlü algoritmalara geçiş yapılmasını kolaylaştırır.
  • Maliyet (cost) ayarını gerektiğinde özelleştirin: Yüksek maliyet daha güvenli fakat daha maliyetlidir; sunucunuzun performansını test edin ve uygun bir cost değeri belirleyin.
  • Migrare ihtiyaçları için password_needs_rehash kullanın: Algoritma veya cost değiştiğinde kullanıcı oturum açtığında hash'i yeniden oluşturup güncelleyin.
  • Parola uzunluğu ve gücü: Minimum uzunluk ve zayıf parola kontrolleri uygulayın; bununla birlikte hash fonksiyonu parola karmaşıklığını sağlamaz, yalnızca saklama güvenliğini sağlar.
  • Veritabanı kolon tipi: Hash'leri saklamak için en azından VARCHAR(255) kullanın; bazı algoritmalar uzun hash'ler üretebilir.
  • Ek güvenlik katmanları: HTTPS zorunlu kılma, rate limiting (brute-force koruması), 2FA ve account lockout politikaları uygulayın.

Yeniden hash (rehash) stratejisi

Algoritma veya cost arttığında mevcut kullanıcı hash'lerini toplu olarak değiştirmek zor olabilir. Bu yüzden yaygın bir strateji şudur:

  • Kullanıcı başarılı giriş yaptığında password_needs_rehash() ile mevcut hash kontrol edilir.
  • Eğer yeniden hash gerekliyse, kullanıcı parolası üzerinden yeni hash üretilip veritabanında güncellenir.
<?php
// Giriş sırasında
if (password_verify($entered, $hash)) {
    if (password_needs_rehash($hash, PASSWORD_DEFAULT)) {
        $newHash = password_hash($entered, PASSWORD_DEFAULT);
        // Veritabanında güncelle
    }
}
?>

Yaygın hatalar ve kaçınılması gerekenler

  • Parolayı düz metin olarak saklamak — kesinlikle yapılmamalıdır.
  • Manuel salt üretme — password_hash otomatik salt üretir; manuel salt karıştırmak hata kaynaklı olabilir.
  • Eski/zayıf hash fonksiyonları kullanma (md5/sha1) — bunlar günümüz saldırılarına dayanıklı değildir.
  • Zamanlama saldırılarına açık manuel karşılaştırmalar — password_verify bunu önler.

Depolama ve operasyonel hususlar

  • Hash'leri veritabanına kaydederken uygun alan uzunluğu ve indeksleme stratejisini düşünün (genelde hash üzerinde arama yapılmaz, kullanıcı adı/email üzerinden arama yapılır).
  • Veritabanı sızıntılarına karşı ek önlemler: sunucu güvenliği, en az yetki prensibi, düzenli yedekleme ve erişim kontrolleri.
  • Giriş denemelerini sınırlayın, IP veya hesap bazlı rate limiting uygulayın.

Sonuç — Özet ve uygulama rehberi

password_hash() ve password_verify() PHP'de parola saklama ve doğrulama için güncel, güvenli ve kolay uygulanabilir bir temel sağlar. Temel adımlar:

  • Kayıt: password_hash ile hash üret, veritabanına kaydet.
  • Giriş: password_verify ile doğrula.
  • Algoritma veya cost değiştiğinde password_needs_rehash ile kullanıcı oturumu esnasında hash'i güncelle.
  • Ek güvenlik: HTTPS, rate limiting, 2FA ve veritabanı güvenliğini unutma.

Bu adımları takip ederek uygulamanızın parola yönetimini modern güvenlik standartlarına yaklaştırabilirsiniz. Parola güvenliği tek başına tüm tehlikeleri ortadan kaldırmaz; katmanlı güvenlik yaklaşımı her zaman daha etkilidir.