- Konu sahibi
- #1
İlk kural, kullanıcı şifresini veritabanına düz metin olarak veya geri döndürülebilir şifreleme ile kaydetmemektir. PHP’de kayıt sırasında
Kayıt veya şifre değiştirme isteğinde kullanıcıdan gelen parolayı önce uygulamanızın parola politikasıyla kontrol edin. Parolayı loglara, oturum verilerine, hata mesajlarına veya başka bir tabloya yazmayın. Ardından
Örneğin tablo alanı şu şekilde tanımlanabilir:
Burada veritabanına kaydedilen değer her kullanıcı için farklı görünebilir. Aynı parola iki kez kullanılsa bile özetlerin farklı olması normaldir; bu durum otomatik üretilen rastgele tuzun çalıştığını gösterir.
Giriş isteğinde veritabanından kullanıcının
Kullanıcı yeni bir parola belirlediğinde eski değeri çözmeye çalışmayın. Yeni parolayı tekrar
PHP’nin varsayılan algoritması ileride değişebileceği için başarılı bir girişten sonra mevcut hash’in güncel seçeneklerle yeniden oluşturulup oluşturulamayacağını kontrol edebilirsiniz. Bunun için
Bu işlem yalnızca eski parola başarıyla doğrulandıktan sonra yapılmalıdır.
Aşağıdaki yöntemler kullanıcı parolası saklamak için uygun değildir:
Son olarak, hash kullanmak giriş güvenliğinin tamamı değildir. Veritabanı sorgularında hazırlanmış ifadeler kullanın, giriş ve kayıt formlarını HTTPS üzerinden çalıştırın, oturum kimliğini başarılı girişten sonra yenileyin ve hata mesajlarında parola ya da hash bilgisi göstermeyin. Temel parola akışı açısından güvenli uygulama; parolanın yalnızca istek sırasında bellekte bulunması, kayıt sırasında
password_hash(), giriş sırasında password_verify() kullanın; oluşan değeri değiştirmeden, en az 255 karakter saklayabilen bir veritabanı sütununa yazın. Böylece veritabanı sızsa bile uygulama şifrelerin kendisini değil, doğrulama için gereken tek yönlü özeti tutar.Kayıt sırasında şifreyi oluşturma
Kayıt veya şifre değiştirme isteğinde kullanıcıdan gelen parolayı önce uygulamanızın parola politikasıyla kontrol edin. Parolayı loglara, oturum verilerine, hata mesajlarına veya başka bir tabloya yazmayın. Ardından
password_hash() ile özetleyip yalnızca bu sonucu veritabanına kaydedin.
PHP:
<?php
$password = $_POST['password'] ?? '';
if ($password === '') {
throw new InvalidArgumentException('Parola boş bırakılamaz.');
}
$passwordHash = password_hash($password, PASSWORD_DEFAULT);
if ($passwordHash === false) {
throw new RuntimeException('Parola özeti oluşturulamadı.');
}
// Örnek: PDO ile veritabanına kaydetme
$stmt = $pdo->prepare(
'INSERT INTO users (email, password_hash) VALUES (:email, :password_hash)'
);
$stmt->execute([
':email' => $email,
':password_hash' => $passwordHash,
]);
PASSWORD_DEFAULT seçimi, uygulamanın PHP’nin önerdiği varsayılan parola algoritmasını kullanmasını sağlar. Bu seçimin ürettiği değerin uzunluğu zaman içinde değişebileceği için password_hash sütununu VARCHAR(255) gibi yeterli genişlikte tanımlayın. Hash değeri, kullanılan algoritma, maliyet ve rastgele tuz bilgilerini kendi içinde taşır; tuzu ayrıca üretmeniz veya ayrı bir tabloda saklamanız gerekmez.Örneğin tablo alanı şu şekilde tanımlanabilir:
SQL:
CREATE TABLE users (
id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
email VARCHAR(255) NOT NULL UNIQUE,
password_hash VARCHAR(255) NOT NULL
);
Burada veritabanına kaydedilen değer her kullanıcı için farklı görünebilir. Aynı parola iki kez kullanılsa bile özetlerin farklı olması normaldir; bu durum otomatik üretilen rastgele tuzun çalıştığını gösterir.
Giriş sırasında şifreyi doğrulama
Giriş isteğinde veritabanından kullanıcının
password_hash değerini alın. Kullanıcının girdiği parolayı yeniden password_hash() ile özetleyip iki metni karşılaştırmayın; rastgele tuz nedeniyle yeni özet farklı çıkabilir. Doğrulama için doğrudan password_verify() kullanın.
PHP:
<?php
$password = $_POST['password'] ?? '';
$stmt = $pdo->prepare(
'SELECT id, password_hash FROM users WHERE email = :email LIMIT 1'
);
$stmt->execute([':email' => $email]);
$user = $stmt->fetch(PDO::FETCH_ASSOC);
if (!$user || !password_verify($password, $user['password_hash'])) {
// Kullanıcıya e-posta veya parola bilgisinin hangisinin hatalı olduğunu söylemeyin.
throw new RuntimeException('E-posta veya parola hatalı.');
}
// Doğrulama başarılı: burada güvenli oturum başlatılır.
session_regenerate_id(true);
$_SESSION['user_id'] = (int) $user['id'];
true sonucu yalnızca verilen parolanın saklanan özetle eşleştiğini gösterir. Kullanıcının hesabının gerçekten ona ait olduğunu, e-posta adresinin doğrulandığını veya hesabın başka güvenlik kontrollerinden geçtiğini tek başına kanıtlamaz. Başarılı doğrulamadan sonra oturum açma, hesap durumu ve gerekirse çok faktörlü doğrulama kontrollerini ayrıca uygulayın. false sonucu ise parola ile kayıtlı özetin eşleşmediği anlamına gelir; kullanıcıya veritabanındaki hash değerini veya ayrıntılı hata nedenini göstermeyin.Şifre değiştiğinde ve algoritma güncellendiğinde ne yapılır?
Kullanıcı yeni bir parola belirlediğinde eski değeri çözmeye çalışmayın. Yeni parolayı tekrar
password_hash() ile özetleyip aynı sütunun üzerine yazın. Yönetici veya destek personeli de mevcut parolayı görememelidir; yalnızca sıfırlama bağlantısı ya da yeni parola belirleme akışı kullanılmalıdır.PHP’nin varsayılan algoritması ileride değişebileceği için başarılı bir girişten sonra mevcut hash’in güncel seçeneklerle yeniden oluşturulup oluşturulamayacağını kontrol edebilirsiniz. Bunun için
password_needs_rehash() kullanılır:
PHP:
if (
password_verify($password, $user['password_hash']) &&
password_needs_rehash($user['password_hash'], PASSWORD_DEFAULT)
) {
$newHash = password_hash($password, PASSWORD_DEFAULT);
$update = $pdo->prepare(
'UPDATE users SET password_hash = :password_hash WHERE id = :id'
);
$update->execute([
':password_hash' => $newHash,
':id' => $user['id'],
]);
}
Bu işlem yalnızca eski parola başarıyla doğrulandıktan sonra yapılmalıdır.
password_needs_rehash() sonucunun true olması, parolanın yanlış olduğunu değil, saklanan hash’in seçtiğiniz güncel algoritma veya seçeneklerle yeniden oluşturulmasının uygun olduğunu gösterir.Kaçınılması gereken yöntemler
Aşağıdaki yöntemler kullanıcı parolası saklamak için uygun değildir:
md5(),sha1()veya doğrudanhash('sha256', $password)kullanmak: Bunlar parola saklama için gereken yavaşlık ve parola-özel tuz yönetimini sağlamaz.- Parolayı düz metin olarak veritabanına yazmak: Veritabanına erişen kişi tüm hesapların parolalarını doğrudan görebilir.
- Parolayı genel amaçlı şifreleme ile saklamak: Uygulamanın çözme anahtarına erişen kişi tüm parolaları geri elde edebilir. Kullanıcı parolası için geri döndürülebilir saklama yerine doğrulanabilir hash kullanılmalıdır.
- Kendi tuzunuzu üretmek veya hash’e sabit bir metin eklemek: PHP’nin parola API’si güvenli rastgele tuzu kendisi oluşturur.
- Hash değerini kısa bir sütuna kesmek: Kesilen değer doğrulamayı bozabilir ve gelecekteki algoritma değişikliklerine yer bırakmaz.
| İhtiyaç | Doğru yaklaşım | Neden |
|---|---|---|
| Kullanıcı parolasını doğrulamak | password_hash() ve password_verify() | Parola geri alınmadan eşleşme kontrol edilir. |
| Kullanıcının sonradan okuyacağı veriyi saklamak | Uygun anahtar yönetimiyle şifreleme | Verinin gerektiğinde çözülmesi gerekir. |
| Eski hash’i güncel seçeneklere taşımak | Başarılı girişten sonra password_needs_rehash() | Yanlış parolayı yeniden hash etmeyi önler. |
password_hash() ile özetlenmesi, girişte password_verify() ile kontrol edilmesi ve veritabanında yalnızca yeterli uzunluktaki hash değerinin tutulmasıdır.