"JWT Kullanıyoruz, Güvenliyiz" Yanılgısı
Authentication dünyasının modern standardı JWT (JSON Web Token). stateless olması, ölçeklenebilirliği harika. Ancak geliştiriciler arasında tehlikeli bir özgüven yaratıyor.
"Token'ı oluştur, client'a ver, o da her istekte göndersin."
Bu kadar basit mi? Peki ya o token çalınırsa? Token'ı localStorage'a koyduğunuzda ne olur? Token'ın süresi (expiration) 7 gün mü olmalı, 15 dakika mı?
Gelin, güvenlik açıklarına (vulnerability) davetiye çıkaran hataları ve production-grade bir JWT mimarisini inceleyelim.
Bölüm 1: JWT Anatomisi ve Yanlış Bilinenler
Bir JWT üç parçadan oluşur: Header.Payload.Signature.
Kritik Bilgi: JWT şifreli (encrypted) değildir, sadece kodlanmıştır (encoded - Base64). Yani Payload kısmına koyduğunuz user_id, email, role gibi bilgiler herkes tarafından okunabilir (jwt.io sitesine yapıştırın ve görün).
Kural 1: Payload içine asla şifre, TC kimlik no, kredi kartı bilgisi gibi PII (Personal Identifiable Information) koymayın.
Bölüm 2: Token Saklama Savaşı (Storage)
Token nerede durmalı?
- localStorage: En kolayıdır ama XSS (Cross-Site Scripting) açığına karşı savunmasızdır. Eğer sitenizde çalışan bir 3. parti JS kütüphanesi (reklam, analytics vb.) zararlı kod içeriyorsa,
localStorage.getItem('token')diyerek token'ınızı çalar ve kendi sunucusuna gönderir. Geçmiş olsun. - Cookie (HttpOnly + Secure): JavaScript bu cookie'ye erişemez. XSS ataklarına karşı token'ınız güvendedir. Ancak bu sefer de CSRF (Cross-Site Request Forgery) riskine karşı önlem almanız gerekir (SameSite=Strict).
Öneri: En güvenli yol, Refresh Token'ı HttpOnly Cookie olarak, Access Token'ı ise hafızada (memory) tutmaktır.
Bölüm 3: Access Token vs Refresh Token
Neden iki tane token var?
- Access Token: Kaynaklara erişim anahtarıdır. Ömrü çok kısa olmalıdır (örn: 15 dakika). Çalınırsa, hırsız sadece 15 dakika kullanabilir.
- Refresh Token: Yeni Access Token almak için kullanılan anahtardır. Ömrü uzundur (örn: 7 gün). Güvenli bir şekilde (HttpOnly Cookie) saklanmalıdır.
Akış (Flow):
- Kullanıcı Login olur -> Sunucu Refresh Token (Cookie) ve Access Token (JSON) döner.
- Client, Access Token ile API'ye istek atar.
- Access Token süresi biter (401 hatası).
- Client, arka planda
/refresh-tokenendpointine gider. Cookie otomatik gider. - Sunucu Refresh Token'ı doğrular ve yeni bir Access Token verir.
- Kullanıcı hiçbir şey hissetmeden oturumu devam eder (Silent Refresh).
Bölüm 4: Token İptali (Logout Problemi)
JWT'nin en büyük sorunu: "Stateless" olduğu için sunucu tarafında oturum bilgisi tutulmaz. Yani "Bu token'ı iptal et" diyemezsiniz. Token süresi dolana kadar geçerlidir.
Peki kullanıcı "Çıkış Yap" butonuna bastığında veya şifresini değiştirdiğinde ne yapacağız?
Çözüm: Token Blacklist (veya Allowlist) Refresh Token'ları veritabanında (veya hızlı olması için Redis'te) saklayın.
- Kullanıcı Logout dediğinde, Redis'teki Refresh Token'ı silin.
- Bir hırsız elindeki çalıntı Refresh Token ile yeni Access Token almaya çalıştığında, sunucu Redis'e bakar, kaydı bulamaz ve isteği reddeder.
Bölüm 5: Yaygın Güvenlik Açıkları
- None Algorithm Attack: Bazı JWT kütüphanelerinde, header kısmındaki
alg: noneyapıldığında imza doğrulaması atlanabiliyordu. Kütüphanelerinizi güncel tutun. - Zayıf Secret Key: Token'ı imzalarken kullandığınız "gizli anahtar" (
process.env.JWT_SECRET) çok karmaşık ve uzun olmalıdır.123456veyasecretyaparsanız, Brute Force ile saniyeler içinde kırılır ve saldırgan kendi sahte "Admin" token'ını üretir.
Sonuç: Paranoyak Olun
Güvenlik, "bir kere kurdum bitti" işi değildir. Katmanlı bir yapıdır.
Checklist:
- [ ] HTTPS kullanıyor muyum? (Token ağda dinlenmesin)
- [ ] Access Token süresi kısa (5-15 dk) mı?
- [ ] Refresh Token HttpOnly Cookie'de mi?
- [ ] Secret Key'im yeterince karmaşık mı?
- [ ] Logout mekanizmam Refresh Token'ı sunucudan siliyor mu?
Authentication mimarisi kurmak, bir binanın temelini atmak gibidir. Temel çürükse, üstüne ne inşa ederseniz edin yıkılır. Güvenli mimariler kurmak konusunda desteğe ihtiyacınız varsa, iletişime geçebilirsiniz.
