2 Ekim 2026 - 10:18
PHP ile Güvenli Beni Hatırla Özelliği: Token ve Çerez Akışı Görseli
PHP

PHP ile Güvenli Beni Hatırla Özelliği: Token ve Çerez Akışı

Yorumlar

Tarayıcıyı kapattıktan sonra hesabın yeniden açılması için PHP oturum çerezinin ömrünü bir aya uzatmak cazip görünür. Fakat uzun süre taşınan aynı oturum kimliğinin iptali ve cihaz bazında yönetimi zorlaşır. “Beni hatırla” seçeneğini ayrı bir kimlik doğrulama kaydı olarak tasarladığınızda, kullanıcı hangi cihazı hatırladığını ve hangi kaydı iptal ettiğini yönetebilir.

Buradaki örnek, HTTPS kullanan PHP uygulamasında parola ile giriş zaten çalışırken eklenecek kalıcı giriş katmanıdır. Normal oturumun taşınması bozuksa önce kaybolan oturum teşhisini tamamlayın. Kalıcı giriş; MFA, kritik işlem öncesi yeniden parola isteme veya hesap yetkilendirmesinin yerine geçmez.

Çereze parola değil, iki parçalı rastgele değer koyun

Çerezin ilk parçası selector, veritabanındaki kaydı bulmak içindir. İkinci parça validator, o kaydı kullanma yetkisini kanıtlar. Veritabanına validator değerinin SHA-256 özeti yazılır. Bu kullanım parola saklamadan farklıdır: validator insanın seçtiği kısa parola değil, 32 bayt kriptografik rastgele değerdir. Kullanıcı parolası için yine password_hash() gerekir.

Aşağıdaki tablo örnek uygulamanıza aittir; blogun içerik tablosu değildir. Her satır bir cihazdaki kalıcı giriş kaydını temsil eder. Bir kullanıcıya birden fazla satır açılabilir. user_id türünü kendi kullanıcı tablonuzla eşleştirin; üretimde uygun yabancı anahtar ve silme politikasını ayrıca ekleyin.

SQL
CREATE TABLE remember_tokens (
    selector CHAR(24) CHARACTER SET ascii COLLATE ascii_bin PRIMARY KEY,
    user_id BIGINT UNSIGNED NOT NULL,
    validator_hash CHAR(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
    auth_version INT UNSIGNED NOT NULL,
    expires_at DATETIME NOT NULL,
    created_at DATETIME NOT NULL,
    INDEX idx_remember_user (user_id),
    INDEX idx_remember_expiry (expires_at)
) ENGINE=InnoDB;

Kayıt yalnızca doğrulanmış girişten sonra oluşturulur

Üye numarasını formdan alıp bu fonksiyona göndermeyin. $userId ve $authVersion, sunucunun parola ve varsa ikinci faktörü doğruladıktan sonra okuduğu kullanıcı satırından gelmelidir. Formdaki “beni hatırla” seçeneği de CSRF korumalı giriş akışının bir parçası olmalıdır. Örnekte token sürelerini UTC tutuyoruz.

PHP
<?php
declare(strict_types=1);
function issueRememberToken(PDO $pdo, int $userId, int $authVersion): string
{
    $selector = bin2hex(random_bytes(12));
    $validator = bin2hex(random_bytes(32));
    $now = new DateTimeImmutable('now', new DateTimeZone('UTC'));
    $stmt = $pdo->prepare(
        'INSERT INTO remember_tokens
        (selector, user_id, validator_hash, auth_version, expires_at, created_at)
        VALUES (?, ?, ?, ?, ?, ?)'
    );
    $stmt->execute([
        $selector, $userId, hash('sha256', $validator), $authVersion,
        $now->modify('+30 days')->format('Y-m-d H:i:s'),
        $now->format('Y-m-d H:i:s'),
    ]);
    return $selector . ':' . $validator;
}
// $pdo: PDO::ERRMODE_EXCEPTION kullanan baglanti.
// $userId ve $authVersion: dogrulanmis kullanici satirindan gelir.

Dönen değeri yanıt başlıkları gönderilmeden önce çereze yazın. Aşağıdaki bölümde $cookieValue, fonksiyonun döndürdüğü değerdir. __Host- öneki için HTTPS, Secure, Path=/ gerekir ve Domain eklenmez.

PHP
<?php
setcookie('__Host-remember', $cookieValue, [
    'expires' => time() + 30 * 24 * 60 * 60,
    'path' => '/',
    'secure' => true,
    'httponly' => true,
    'samesite' => 'Lax',
]);

Çerez ömrü istemci davranışını belirler; izin kararında veritabanındaki süreyi esas alın. Bilgisayar saati veya elle düzenlenmiş bir çerez, sunucudaki son kullanım tarihini uzatmamalıdır. Tokenı URL parametresine, analiz aracına veya uygulama loguna taşımayın.

Otomatik girişte kontrol sırası

Normal, geçerli bir oturum varsa kalıcı tokenı her istekte kullanmak gerekmez. Oturum yoksa önce çerezin biçimini doğrulayın. Bu küçük fonksiyon bozuk çerezi SQL sorgusuna gelmeden reddeder; kimlik doğrulama yapmaz.

PHP
<?php
function splitRememberCookie(string $value): ?array
{
    if (!preg_match('/\A([a-f0-9]{24}):([a-f0-9]{64})\z/D', $value, $m)) {
        return null;
    }
    return ['selector' => $m[1], 'validator' => $m[2]];
}
  1. Selector ile token kaydını bulun; süreyi kontrol edin.
  2. Kullanıcıyı okuyup hesabın aktif olduğunu ve tokenın auth_version değerinin güncel hesap değeriyle eşleştiğini doğrulayın.
  3. Gelen validator özetini, saklanan özetle hash_equals() kullanarak karşılaştırın.
  4. Başarılı tüketim ve yeni token üretimini aynı veritabanı işlemi içinde yapın. Eski tokenı geçersiz kılın.
  5. İşlem tamamlanınca yeni çerezi gönderin ve yeni oturuma doğrulanmış kullanıcı kimliğini yazın. Kullanıcının yönetim yetkisini çerezden okumayın.

Karşılaştırmanın çekirdeği şöyledir; $row veritabanındaki token satırı, $parts ayrıştırma fonksiyonunun çıktısıdır:

PHP
<?php
$valid = hash_equals(
    $row['validator_hash'],
    hash('sha256', $parts['validator'])
);

İki paralel istek aynı tokenı kullanırsa

Tarayıcı bir sayfayla birlikte birkaç API isteği açabilir. Hepsi aynı kalıcı tokenı tüketmeye çalışırsa ilk istek yenilemeyi tamamlar, ikinci istek artık eski tokenı taşır. İkinci yanıtın kontrolsüz biçimde çerezi silmesi, ilk yanıtın yeni çerezini de ezebilir.

Basit uygulamada otomatik girişi tek bir başlangıç isteğinde tamamlayıp diğer istekleri bu akıştan sonra başlatın. Sunucuda kullanıcı satırını, ardından token satırını FOR UPDATE ile kilitleyerek tüketimi sıraya alın; bütün hesap işlemlerinde aynı kilit sırasını koruyun. Büyük uygulamalarda token ailesi, yeniden kullanım tespiti ve eşzamanlı istek politikası ayrıca tasarlanmalıdır. Bu yazıdaki üretim fonksiyonu, tek başına tamamlanmış otomatik giriş denetleyicisi değildir.

Giriş anında oturum kimliğini yenilerken eski anonim oturuma kullanıcı kimliğini önceden yazmayın. Kimlik yenileme başarısızsa giriş yetkisi vermeyin. Mobil bağlantı ve eşzamanlı istekler için eski oturum kaydının kullanımını zaman damgasıyla yönetmek gerekir; her istekte koşulsuz yenileme yapmak çözüm değildir.

Çıkış ve süre dolması nasıl denenir?

Bir test hesabıyla iki tarayıcı profili kullanın. İlkinde “beni hatırla” seçili giriş yapın, ikincisinde seçmeyin. İlk profilin yalnızca normal oturum çerezini silip sayfayı tekrar açtığınızda otomatik giriş çalışmalı; ikinci profilde giriş ekranı görünmelidir. Ardından ilk kaydın süresini test veritabanında geçmişe alın: çerez tarayıcıda dursa bile erişim reddedilmelidir.

Tek cihazdan çıkışta o cihazın token satırını ve çerezini kaldırın. Tüm cihazlardan çıkışta kullanıcıya ait bütün tokenları iptal edin ve oturum sürümünü artırın. Bu iki davranışın örnekleri güvenli çıkış yazısında bulunuyor.

Başvuru: PHP kalıcı giriş ve oturum ayarları, setcookie, çerez önekleri.

Benzer Yazılar

Yorumlar ()

Henüz yorum yok. İlk yorum yapan sen ol!

Yorum Yap