İçeriğe geç
Muhammet Şafak
Web Geliştirme 3 dk okuma

JWT Authentication

JWT (JSON Web Token) ile kimlik doğrulama: token yapısı, çalışma mantığı ve tipik kullanım senaryoları.


JWT, modern web uygulamalarında kimlik doğrulamanın varsayılan aracı haline geldi. Bu yaygınlık iyi bir şey; ama “varsayılan” olması, her durumda doğru seçim olduğu anlamına gelmiyor. Bu yazıda JWT’nin nasıl çalıştığını, ne zaman işe yaradığını ve yıllar içinde gördüğüm tipik hataları aktarıyorum.

JWT nedir, neyi çözer

JWT (JSON Web Token), iki taraf arasında doğrulanabilir biçimde bilgi taşıyan bir token formatıdır. Nokta ile ayrılmış üç bölümden oluşur:

header.payload.signature

header token türünü ve imzalama algoritmasını söyler; payload taşınan veriyi tutar; signature ise ilk iki bölümün gizli bir anahtarla imzalanmış halidir. İmza sayesinde sunucu, token içeriğinin değiştirilmediğini — anahtarı kimseyle paylaşmadan — doğrulayabilir.

JWT’nin çözdüğü asıl problem şu: sunucu, oturum bilgisini kendi tarafında saklamak zorunda kalmaz. Token kendi kendini doğrular. Bu, birden çok sunucuya yayılmış bir sistemde oturumu paylaşma derdini ortadan kaldırır.

Bedeli ne

Bu durumsuzluk bedava değil. Stateful bir oturumda kullanıcıyı anında atabilirsiniz — kaydı silersiniz, biter. JWT’de token, siz ne yaparsanız yapın, süresi dolana kadar geçerlidir. Ele geçirilmiş bir token’ı geri çağırmak, JWT’nin doğası gereği zordur.

Bu yüzden JWT’yi şöyle konumlandırıyorum: kısa ömürlü erişim için iyi; “oturumu her an anında iptal edebilmem gerek” diyen senaryolar için zayıf.

Bu zayıflığı bir kara liste (blacklist) ile yamayabilirsiniz — iptal edilen token’ları bir yerde tutup her istekte kontrol edersiniz. Ama dikkat edin: o an JWT’nin baştaki vaadini, yani “sunucu hiçbir oturum durumu tutmasın” ilkesini terk etmiş olursunuz. Kara liste eklediğiniz noktada, durumsuzluğun getirdiği kolaylığın bir kısmını geri vermiş olursunuz. Bu kötü bir karar değil; ama bilinçli verilmesi gereken bir karar.

Pratikte: imzalama ve doğrulama

Konuyu somutlaştırmak için imzalama ve doğrulamayı elle yapan küçük bir sınıf. Production’da bunu kendiniz yazmayın — firebase/php-jwt gibi denenmiş bir paket kullanın; aşağıdaki yalnızca mekanizmayı göstermek için:

class JWT
{
    protected const ALGORITHM = 'HS256';
    protected const SIGNATURE_ALGORITHM = 'sha256';

    public static function encode(string $key, array $payload, ?int $ttl = null): string
    {
        $header = base64_encode(json_encode([
            'typ' => 'JWT',
            'alg' => self::ALGORITHM,
        ]));
        $payload = base64_encode(json_encode([
            'data'       => $payload,
            'created_at' => time(),
            'ttl'        => $ttl,
        ]));

        return $header . '.' . $payload . '.' . self::signature($key, $header, $payload);
    }

    public static function decode(string $key, string $jwt): array|false
    {
        try {
            [$h, $p, $signature] = explode('.', $jwt);
            if (!hash_equals(self::signature($key, $h, $p), $signature)) {
                return false;
            }
            $payload = json_decode(base64_decode($p), true);
            if ($payload['ttl'] !== null && time() - $payload['created_at'] > $payload['ttl']) {
                return false;
            }
            return $payload['data'];
        } catch (\Throwable) {
            return false;
        }
    }

    private static function signature(string $key, string $header, string $payload): string
    {
        return base64_encode(hash_hmac(self::SIGNATURE_ALGORITHM, $header . '.' . $payload, $key, true));
    }
}

Burada gözden kaçmaması gereken bir satır var: imza karşılaştırmasını hash_equals() ile yapıyorum, == ile değil. Sıradan karşılaştırma, yanıt süresinden bilgi sızdıran zamanlama saldırılarına (timing attack) açıktır. Küçük bir detay; ama güvenlik kodunda “küçük detay” diye bir şey yok.

Yıllar içinde gördüğüm hatalar

  • Uzun ömürlü token. Erişim token’ı 15 dakika–1 saat arası olmalı; kalıcı oturum için ayrı, daha uzun ömürlü bir refresh token kullanın.
  • Yanlış yerde saklamak. Token’ı localStorage’a koymak onu XSS’e açar. HttpOnly ve Secure bir cookie daha güvenlidir.
  • Payload’a hassas veri koymak. payload imzalıdır ama şifreli değildir — Base64 çözen herkes okuyabilir. Parola, kimlik numarası gibi şeyler oraya yazılmaz.
  • alg: none ihtimalini unutmak. Doğrulama tarafı algoritmayı token’ın kendisinden körü körüne okursa, saldırgan imzayı tamamen atlayabilir. Beklediğiniz algoritmayı kodda sabitleyin, token’a güvenmeyin.

Özet

JWT zarif bir mekanizma; ama sihir değil. Durumsuzluğun getirdiği ölçeklenme kolaylığını, iptal etme zorluğu olarak geri ödüyorsunuz. Token’ları kısa tutarsanız, doğru yerde saklarsanız ve imzayı titizce doğrularsanız, bu takas çoğu uygulama için makul. Bu koşulları sağlayamıyorsanız, klasik sunucu oturumu hâlâ saygın bir seçenektir — yeni olan, her zaman daha iyi anlamına gelmiyor.

Etiketler: #JWT
Paylaş:

İlgili Yazılar

Sitede Ara

Yazı, proje ve sayfalarda arama yapmak için yazmaya başlayın.

Esc ile kapat Pagefind ile güçlendirildi