Application Security

JWT Döngüsü ve İptali: Durumsuz Mimari İçin

Durumsuz mimarilerde JSON Web Token'larının (JWT) uygulanması önemli ölçeklenebilirlik avantajları sunar ancak token çalınması gibi kritik bir güvenlik açığı da yaratır. Oturum tabanlı sistemlerin aksine, sunucunun istemci tarafında bir oturumu anında geçersiz kılabilmesi mümkün değildir; JWT'ler kendi kendine yeterli (self-contained) yapıdadır. Bir kez verildikten sonra, sunucu kullanıcının oturumunu kapatması gerektiğine karar verse bile, süresi dolana kadar geçerli olmaya devam ederler. Bu yazıda, token döngüsü ve seçici iptal yoluyla bu riski azaltmaya yönelik sağlam stratejiler ele alınmaktadır.

Durumsuzluk İkilemi

Geleneksel bir durumsuz ortamda sunucu, kullanıcı durumunu saklamaz. JWT, tüm gerekli iddiaları (claims) içeren gerçeklik kaynağı olarak görev yapar. Ancak bir saldırgan, XSS veya ağ dinleme yoluyla bir erişim token'ını çalarsa, kısa süresi dolana kadar bunu kullanabilir. Erişim token'ının ömrünü (örneğin 15 dakika) sınırlamak yardımcı olsa da, bu durum kullanıcı deneyimi açısından sürtüşmeye yol açar. İşte burada Erişim Tokenı/Yenileme Tokenı deseni hayati önem kazanır.

Kısa ömürlü erişim tokenları ve uzun ömürlü yenileme tokenları vererek, saldırganların fırsat penceresini daraltırız. Erişim tokenı API isteklerini yönetirken, yenileme tokenı yalnızca yeni erişim tokenları almak için kullanılır. Kritik olarak, yenileme tokenı JavaScript erişimini önlemek amacıyla tercih edilen HTTP-only çerezlerde güvenli bir şekilde saklanmalıdır.

Token Döngüsünün Uygulanması

Token döngüsü, bir yenileme tokenı kullanıldığında her seferinde yeni bir yenileme tokenı verilmesi uygulamasıdır. Bu strateji, çalınan bir yenileme tokenının değerini minimize eder. Bir saldırgan bir yenileme tokenını çalarsa, meşru kullanıcının bir sonraki yenileme denemesi çalınan tokenı geçersiz kılana kadar yalnızca tek bir istekte bulunabilir.

Aşağıda, döngü mantığını gösteren basitleştirilmiş bir Node.js örneği bulunmaktadır:

async function handleRefreshToken(req, res) {
  const { refreshToken } = req.body;
  
  // 1. Token imzasını ve süresini doğrula
  const decoded = jwt.verify(refreshToken, REFRESH_SECRET);
  
  // 2. Token depomuzda (Redis) var mı diye kontrol et
  const storedToken = await redis.get(`refresh:${decoded.jti}`);
  if (!storedToken) {
    return res.status(401).send('Yenileme tokenı iptal edildi veya geçersiz');
  }
  
  // 3. YENİ erişim ve yenileme tokenları ver
  const newAccessToken = generateAccessToken(decoded.userId);
  const newRefreshToken = generateRefreshToken(decoded.userId);
  
  // 4. Yeni yenileme tokenını sakla ve eskisini sil
  await redis.setEx(`refresh:${newJti}`, EXPIRY, newRefreshToken);
  await redis.del(`refresh:${decoded.jti}`);
  
  res.json({ accessToken: newAccessToken, refreshToken: newRefreshToken });
}

İptal Stratejileri

Döngüye rağmen, şifre değişikliği veya hesap ihlali bildirimi gibi durumlarda anında iptal gerekli olabilir. JWT'ler durumsuz olduğundan, bunları basitçe "silemeyiz". Erişim vermeden önce geçerliliklerini kontrol etmemizi sağlayacak bir yola ihtiyacımız var.

1. Kısa Ömürlü Erişim Tokenları

En etkili önlem, erişim tokenlarını çok kısa ömürlü tutmaktır (5-15 dakika). Bu, bir token çalınmış olsa bile saldırganın onu istismar edebileceği pencerenin çok sınırlı olmasını sağlar. Bu yaklaşımı döngü ile birleştirerek, pencereyi pratikte yok denecek kadar azaltabilirsiniz.

2. Token Kara Listesi (Red Listesi)

Anında çıkış yapılması gereken senaryolar için, iptal edilen token kimliklerini (JTI) içeren bir kara liste tutabiliriz. Bir kullanıcı çıkış yaptığında, JTI, tokenın kalan süresine eşit bir TTL ile bir Redis kümesine eklenir. Her istek sırasında sunucu, JTI'nin kara listede olup olmadığını kontrol eder.

function isValidToken(jti, token) {
  // Önce kara listeyi kontrol et
  if (redis.sIsMember('token_denylist', jti)) {
    return false;
  }
  return true;
}

Bu yaklaşım çok küçük bir gecikme maliyeti ekler ancak güvenliği sağlar. Yüksek trafikli sistemlerde, Redis'in O(1) zaman karmaşıklığıyla bu kontrolleri ele almasını sağlayarak kara liste işlemlerinin optimize edildiğinden emin olun.

Sonuç

Durumsuz mimarileri güvence altına almak, basit JWT yayınlamanın ötesine geçmeyi gerektirir. Kısa ömürlü erişim tokenları, agresif yenileme tokenı döngüsü ve hedefli iptal mekanizmalarını birleştirerek geliştiriciler, token çalınmasının etkisini önemli ölçüde azaltabilir. Unutmayın, güvenlik kullanılabilirlik ile risk arasındaki dengeyi gerektirir. Bu stratejileri uygulamak, JWT'lerin ölçeklenebilirlik avantajlarından ödün vermeden uygulamanızın modern tehditlere karşı dirençli kalmasını sağlar.

Share: