JSON Web Token Tanımı ve Temel Bileşenlerini Anlama

JSON Web Token (JWT), taraflar arasında güvenli bir şekilde bilgi iletmek için kullanılan, açık bir endüstri standardı olan kompakt ve kendi kendini tanımlayan bir token formatıdır. Bu bilgi, JSON nesnesi olarak kodlanır ve dijital imza veya şifreleme ile doğrulanır ve güvenli hale getirilir. JWT'ler, özellikle kimlik doğrulama (authentication) ve yetkilendirme (authorization) senaryolarında yaygın olarak kullanılır.

Bir JWT'nin temel bileşenleri üç ana bölümden oluşur ve bunlar nokta (.) karakteri ile birleştirilir: Header, Payload ve Signature. Header kısmı, token'ın türünü ve kullanılan imzalama algoritmasını (örneğin HMAC SHA256 veya RSA) tanımlar. Payload, taşınan verileri içerir; bu veriler "claims" (iddialar) olarak adlandırılır ve kullanıcı kimliği, süresi (exp) gibi bilgileri barındırır. Signature ise, önceden tanımlanmış bir gizli anahtar (secret) veya özel anahtar (private key) kullanılarak, header ve payload'ın bütünlüğünü doğrulamak için oluşturulur.

Bileşen Açıklama Örnek İçerik (Kodlanmış Öncesi)
Header Token meta verisi ve algoritma bilgisi. {"alg": "HS256", "typ": "JWT"}
Payload Taşınan veri (claims). {"sub": "1234567890", "name": "John Doe", "iat": 1516239022}
Signature Header ve payload'ın bütünlük doğrulaması. HMACSHA256(base64UrlEncode(header) + "." + base64UrlEncode(payload), secret)

JWT'nin Çalışma Prensibi ve Akışı

JWT tabanlı kimlik doğrulamanın çalışma prensibi, istateless (durumsuz) olmasına dayanır. Bu, sunucunun kullanıcı oturum durumunu (session) saklamasına gerek olmadığı anlamına gelir. Kullanıcı kimlik bilgilerini (örn. kullanıcı adı/şifre) gönderdiğinde, sunucu bu bilgileri doğrular ve geçerli bir JWT oluşturarak istemciye (genellikle tarayıcı veya mobil uygulama) yanıt olarak döndürür. İstemci, bu token'ı alır ve sonraki isteklerinde, genellikle Authorization başlığı ile "Bearer {token}" formatında sunucuya gönderir.

Sunucu, gelen istekteki JWT'yi alır, imzasını ve süresini (exp) kontrol eder. İmza doğrulaması başarılıysa ve token süresi dolmamışsa, sunucu payload içerisindeki claims'lere (örneğin kullanıcı ID'si) güvenir ve isteği işler. Bu mekanizma, sunucu tarafında oturum veritabanı sorgularını ortadan kaldırarak ölçeklenebilirliği artırır. Ancak, token'ın çalınması (token theft) riskine karşı, kısa süreli erişim token'ları (access token) ve yenileme token'ları (refresh token) gibi stratejiler geliştirilmiştir.

Bu akışı adım adım incelemek gerekirse:

  • 1. İstemci, kimlik bilgileriyle giriş yapar. Kullanıcı adı ve şifre gibi bilgiler, güvenli bir kanal (HTTPS) üzerinden kimlik doğrulama sunucusuna iletilir.
  • 2. Sunucu kimlik doğrular ve JWT üretir. Sunucu, veritabanında kimlik doğrulamayı yapar, ardından benzersiz kullanıcı bilgilerini (claims) içeren bir JWT oluşturur ve bunu imzalar.
  • 3. JWT istemciye iletilir. Oluşturulan token, genellikle JSON yanıtının gövdesinde veya bir HTTP-only cookie içinde istemciye geri gönderilir.
  • 4. İstemci, JWT'yi sonraki isteklerinde gönderir. İstemci, bu token'ı alır ve API'ye yapacağı her yeni istekte Authorization başlığına ekler.
  • 5. Kaynak sunucu, JWT'yi doğrular ve isteği işler. İstek geldiğinde, kaynak sunucu (API sunucusu) token'ın imzasını ve geçerliliğini kontrol eder. Başarılı olursa, payload'daki bilgilere dayanarak isteği yetkilendirir ve yanıt oluşturur.

Bu prensip, özellikle mikroservis mimarileri veya tek sayfalı uygulamalar (SPA) gibi modern geliştirme paradigmalarında son derece etkilidir. Merkezi bir oturum deposuna bağımlılığı ortadan kaldırarak, her servisin bağımsız olarak gelen token'ı doğrulayabilmesini sağlar. Bu da dağıtık sistemlerin yönetimini ve ölçeklendirilmesini büyük ölçüde kolaylaştırır.

JWT Yapısı: Header, Payload, Signature

Bir JWT'nin teknik yapısı, noktalarla ayrılmış üç ayrı Base64Url kodlanmış dizeden oluşur: `Header.Payload.Signature`. Bu format, token'ın hem kompakt hem de URL-safe (URL'de güvenle kullanılabilir) olmasını sağlar. Her bir bölümün rolü ve içeriği, token'ın güvenliği ve işlevselliği açısından kritik öneme sahiptir.

İlk bölüm olan Header (başlık), genellikle iki parçadan oluşur: token'ın türünü (`typ`) belirten "JWT" ve imzalama veya şifreleme için kullanılan algoritmayı (`alg`) tanımlayan bir parametre (örneğin, `HS256`, `RS256`). Algoritma seçimi, token'ın nasıl doğrulanacağını belirler. `HS256` (HMAC with SHA-256) simetrik bir anahtar kullanırken, `RS256` (RSA Signature with SHA-256) asimetrik bir anahtar çifti (public/private key) kullanır. Header Base64Url ile kodlanarak JWT'nin ilk kısmını oluşturur.

Payload (yük), token ile taşınan verileri içeren ikinci bölümdür. Bu verilere "claims" (iddialar) adı verilir ve üç türde olabilir: registered claims, public claims ve private claims. Registered claims, önceden tanımlanmış ve opsiyonel olarak kullanılan, `iss` (issuer), `exp` (expiration time), `sub` (subject) gibi standart alanlardır. Public claims, JWT kullanıcıları tarafından tanımlanabilen, çakışmayı önlemek için genellikle bir URI ile isimlendirilen alanlardır. Private claims ise, bilgi alışverişi yapan tarafların kendi aralarında anlaştığı özel veriler için kullanılır. Payload'daki tüm bilgiler okunabilirdir, bu nedenle asla şifre gibi hassas veriler payload'da saklanmamalıdır.

Üçüncü ve en kritik bölüm olan Signature (imza), token'ın bütünlüğünü ve gerçekliğini sağlar. İmza oluşturmak için, kodlanmış header, kodlanmış payload ve bir gizli (secret) veya özel anahtar (private key) kullanılır. İmza, header'da belirtilen algoritmaya göre (ör. HMAC SHA256) şu şekilde hesaplanır: `HMACSHA256( base64UrlEncode(header) + "." + base64UrlEncode(payload), secret)`. Bu imza, header veya payload'taki tek bir karakter değişse bile tamamen farklı olacaktır. Alıcı (sunucu), token'ı aldığında, aynı algoritma ve gizli anahtarı kullanarak imzayı yeniden hesaplar. Hesaplanan imza, token'daki imza ile eşleşirse, mesajın gönderen tarafından değiştirilmediğinden ve güvenilir kaynaktan geldiğinden emin olur.

Claim Türü Açıklama Örnek Anahtar & Değer
Registered IANA JSON Web Token Claims sicilinde önceden tanımlanmıştır. "exp": 1735689600 (Süre Sonu Zaman Damgası)
Public Çakışmasız isimlerle (örn. URI) herkese açık tanımlanabilir. "https://example.com/is_admin": true
Private Uygulamaya özel, taraflar arasında anlaşılmış veriler. "department": "Engineering"

İmzanın doğrulanması, JWT güvenliğinin temel taşıdır. Simetrik imzalama (`HS256`) için, imzalama ve doğrulama aynı gizli anahtarı kullanır; bu nedenle anahtarın güvenliği çok önemlidir. Asimetrik imzalama (`RS256`) ise, token'ı yalnızca özel anahtara sahip sunucu imzalayabilir, ancak herkes sunucunun herkese açık anahtarını kullanarak token'ın geçerliliğini doğrulayabilir. Bu, daha karmaşık ancak merkezi anahtar yönetimi açısından daha güvenli bir senaryo sağlar.

JWT Güvenliği ve En İyi Uygulamalar

JWT'lerin güvenli kullanımı, tasarım ve uygulama aşamasında dikkat edilmesi gereken bir dizi kritik unsura bağlıdır. Token'ın çalınması, ifşa olması veya yetkisiz kullanımı, tüm uygulama güvenliğini tehlikeye atabilir. Bu nedenle, güçlü imzalama algoritmalarının seçilmesi ilk adımdır. HS256, RS256 veya ES256 gibi güvenli kabul edilen algoritmalar kullanılmalıdır. Asla `alg` alanını `"none"` olarak ayarlamamalı veya zayıf algoritmalar kullanmamalısınız.

Token'ın geçerlilik süresinin (`exp` claim) doğru ve kısa tutulması hayati önem taşır. Uzun süreli erişim token'ları (access token), ele geçirildiklerinde uzun bir süre boyunca yetkisiz erişim sağlayabilir. Bu riski azaltmak için Access Token ve Refresh Token modeli benimsenmelidir. Kısa ömürlü (dakikalar/saatler) bir Access Token, uzun ömürlü bir Refresh Token ile birlikte verilir. Access Token süresi dolduğunda, istemci Refresh Token'ı kullanarak yeni bir Access Token alabilir. Refresh Token daha sıkı güvenlik önlemleri (ör. güvenli, HTTP-only cookie'de saklama) ile korunmalıdır.

İmza doğrulaması her zaman sunucu tarafında yapılmalıdır. İstemci tarafında saklanan bir JWT asla güvenilir bir veri kaynağı olarak kabul edilmemelidir. Sunucu, gelen her token için imzayı, süreyi (`exp`, `nbf`) ve yayıncıyı (`iss`) mutlaka doğrulamalıdır. Ayrıca, token'ın yeniden kullanılmasını (replay attack) önlemek için, kullanılmış token'ların bir kara liste (blacklist) veya jeton kimliği (`jti` claim) kullanılarak takip edilmesi düşünülebilir, ancak bu `stateless` felsefesine kısmen ters düşer.

  • Güvenli Taşıma: JWT'ler her zaman HTTPS (TLS/SSL) üzerinden iletilmelidir. Aksi takdirde, token kolayca ele geçirilebilir.
  • Payload Güvenliği: Payload, Base64Url ile kodlanmış olsa da şifrelenmemiştir. Hassas kullanıcı verileri (TCKN, kredi kartı) asla eklenmemelidir.
  • Secret/Key Yönetimi: HS256 için kullanılan gizli anahtar yeterince karmaşık ve rastgele olmalı, güvenli bir şekilde saklanmalıdır. RS256 için özel anahtar sızıntısı engellenmelidir.
  • Çıkış Mekanizması: Kullanıcı çıkış yaptığında (logout), istemci tarafında token silinir, ancak sunucu tarafında hala geçerlidir. Anında geçersiz kılma için kısa token ömrü veya özel bir token iptal listesi gerekebilir.

JWT'lerin depolanma şekli de güvenliği etkiler. Web uygulamalarında, XSS (Cross-Site Scripting) saldırılarına karşı koruma sağlamak için, token'ları tarayıcının `localStorage` veya `sessionStorage`'ında saklamak riskli olabilir. Bunun yerine, `httpOnly`, `secure` ve `sameSite` öznitelikleri ayarlanmış bir cookie içinde saklamak, XSS ile token çalınması riskini önemli ölçüde azaltır. Ancak, bu durumda CSRF (Cross-Site Request Forgery) saldırılarına karşı da önlem alınmalıdır.

Son olarak, kullanılan kütüphanelerin güncel ve güvenilir olmasına dikkat edilmelidir. JWT işlemleri için iyi bakılan, popüler kütüphaneler kullanılmalı ve bu kütüphanelerin güvenlik güncellemeleri takip edilmelidir. Özelleştirilmiş, "ev yapımı" JWT kodlama/çözme mantığı yazmaktan kaçınılmalı, standartlara uygun, test edilmiş çözümler tercih edilmelidir. Bu önlemlerin tümü, JWT tabanlı bir sistemin güvenlik duvarlarını güçlendirmek için gereklidir.

JWT ile Session ve Diğer Token Türleri Karşılaştırması

JWT'ler, geleneksel sunucu tarafı oturum yönetimi (session) ve diğer token formatlarıyla karşılaştırıldığında, belirgin avantaj ve dezavantajlara sahiptir. Bu karşılaştırma, bir uygulama mimarisi tasarlanırken hangi yaklaşımın seçileceğine dair kritik bilgiler sağlar. Geleneksel session-based authentication modelinde, sunucu kullanıcının kimlik durumunu (genellikle bellek veya bir veritabanında) saklar ve istemciye yalnızca bir oturum kimliği (session ID) içeren bir cookie gönderir.

Bu modelin en büyük farkı stateful (durumlu) olmasıdır. Sunucu, her istekte gelen session ID'yi kontrol ederek, ilişkili oturum verilerine erişir ve kullanıcıyı doğrular. Bu, sunucu tarafında merkezi bir oturum deposu gerektirir ve bu deponun ölçeklenmesi, yük dengeleme yapılan ortamlarda ekstra dikkat gerektirebilir. Buna karşılık, JWT tabanlı yaklaşım stateless'tir. Sunucu, kullanıcı durumunu token'ın kendisinde taşıdığı için herhangi bir oturum verisi saklamaz. Bu, sunucu yükünü azaltır ve uygulamanın yatay olarak ölçeklenmesini son derece kolaylaştırır. Ancak, JWT'nin boyutu daha büyüktür ve istemciden sunucuya her istekte gönderilmesi gerektiğinden, geleneksel bir session cookie'sine göre daha fazla bant genişliği kullanabilir.

Diğer token türleri arasında ise Opaque Tokens (opak token'lar) öne çıkar. Opaque token'lar, genellikle rastgele bir dizedir ve kendi içlerinde herhangi bir anlamlı veri taşımazlar. JWT'den farklı olarak, bir opak token'ın geçerliliğini ve içeriğini doğrulamak için, onu veren yetkilendirme sunucusuna (authorization server) her seferinde bir "introspection" (içe bakış) isteği göndermek gerekir. Bu, sunucu tarafında durum kontrolü gerektirdiği anlamına gelir, ancak token'ın anında iptal edilmesi gibi bir avantaj sağlar. JWT'ler ise, kendi kendine yeten yapıları sayesinde bu merkezi sorgu ihtiyacını ortadan kaldırır. Bu, performans ve ölçeklenebilirlik açısından JWT'ye avantaj sağlarken, token iptali konusunda bir zorluk yaratır.

Güvenlik açısından bakıldığında, session ID'ler XSS saldırılarıyla çalınsa bile, sunucu tarafında iptal edilebilirler. JWT'ler ise, süresi dolana kadar teknik olarak geçerlidir. Session cookie'leri, `httpOnly` bayrağı ile korunarak JavaScript erişimine kapatılabilir, bu da XSS'ten çalınma riskini büyük ölçüde azaltır. JWT'ler ise genellikle client-side storage'da saklandığı için XSS'e karşı daha savunmasızdır, ancak doğru cookie stratejisi ile bu risk hafifletilebilir. Ayrıca, session yaklaşımı CSRF saldırılarına daha açıkken, JWT'nin Authorization header'ında taşınması bu riski doğal olarak ortadan kaldırır.

Modern Yazılım Mimarilerinde JWT Kullanım Senaryoları

JWT'lerin benzersiz özellikleri, onları modern ve dağıtık yazılım mimarileri için ideal bir seçim haline getirir. Tek Sayfalı Uygulamalar (SPA) ve mobil uygulamalar, JWT'nin en yaygın kullanıldığı alanlardır. Bu istemciler, bir backend API'si ile iletişim kurar ve sunucu tarafında oturum sürdürmek pratik değildir. JWT sayesinde, istemci kimlik doğrulamasını yaptıktan sonra aldığı token'ı her API isteğine ekler ve API sunucusu, herhangi bir durum sorgulaması yapmadan kullanıcıyı tanıyıp isteği işleyebilir. Bu, istek başına düşen yükü ve gecikmeyi azaltır.

Mikroservis Mimarileri, JWT'nin değerini en iyi şekilde gösteren başka bir senaryodur. Dağıtık bir sistemde, bir kullanıcı isteği birden fazla bağımsız servisi dolaşabilir. Geleneksel bir session yaklaşımında, her servisin merkezi bir oturum deposuna erişmesi veya oturum verilerini kendi aralarında senkronize etmesi gerekir ki bu karmaşık ve hataya açıktır. JWT ile, kimlik doğrulamasını yapan "Authentication Service", kullanıcı bilgilerini ve izinlerini içeren bir JWT oluşturur. Kullanıcı bu token'ı alır ve ilk mikroservise (örneğin "Sipariş Servisi") istek yapar. Bu servis, token'ın imzasını kendi elindeki genel anahtar veya gizli anahtar ile doğrular. Daha sonra, aynı token'ı, kullanıcı adına işlem yapması gereken bir sonraki mikroservise (örneğin "Ödeme Servisi") iletebilir. Bu sayede, her servis kullanıcı bağlamından bağımsız olarak haberdar olur ve merkezi bir koordinasyona ihtiyaç duymaz.

JWT'ler, API Gateway veya Reverse Proxy katmanlarında yetkilendirme için de mükemmel bir araçtır. Gateway, gelen istekteki JWT'yi doğrulayabilir, `exp` gibi claim'leri kontrol edebilir ve hatta belirli rotalara (endpoints) erişimi kısıtlamak için `scope` veya `role` claim'lerini kullanabilir. Bu, arka uç servislerinin kimlik doğrulama ve temel yetkilendirme mantığından tamamen kurtulmasını sağlayarak, bu servislerin yalnızca iş mantığına odaklanmasına olanak tanır. Ayrıca, üçüncü taraf API entegrasyonlarında ve OAuth 2.0 / OpenID Connect (OIDC) protokollerinde JWT standart bir bileşendir. OIDC'deki Kimlik Token'ı (ID Token) doğrudan bir JWT'dir ve kullanıcı hakkında standartlaştırılmış bilgiler taşır. OAuth 2.0'da da erişim token'ları (access token) genellikle JWT formatında olabilir, bu da kaynak sunucuların token'ı bağımsız olarak doğrulamasına izin verir.

Son bir senaryo olarak, Sunucusuz (Serverless) Mimarilerde JWT'lerin rolü büyüktür. AWS Lambda veya Azure Functions gibi geçici ve durumsuz işlevlerde, geleneksel bir oturum mekanizmasını sürdürmek pratik değildir. Her fonksiyon çağrısı, kendisine iletilen JWT'yi hızlıca doğrulayabilir ve içerdiği claims'lere göre işlemi gerçekleştirebilir. Bu, sunucusuz işlevlerin hızlı başlatılması ve yatay ölçeklenmesi ile mükemmel bir uyum sağlar. Tüm bu senaryolar, JWT'nin modern, dağıtık ve mikroservis odaklı uygulama ekosisteminde neden vazgeçilmez bir standart haline geldiğini açıkça göstermektedir.

Potansiyel Riskler ve Azaltma Stratejileri

JWT kullanımı beraberinde önemli güvenlik riskleri getirir ve bu risklerin proaktif olarak yönetilmesi gerekir. En kritik risklerden biri, token'ın yetkisiz bir tarafça ele geçirilmesidir (token theft). Eğer bir JWT çalınırsa ve süresi dolmamışsa, saldırgan token'ı kullanarak sanki orijinal kullanıcıymış gibi sisteme erişim sağlayabilir. Bu risk, özellikle token'ın istemci tarafında JavaScript erişilebilir bir yerde (localStorage) saklanması durumunda, XSS saldırıları yoluyla artar. Bir diğer büyük risk, token'ın içerdiği bilgilerin gizliliğinin ihlalidir. JWT payload'ı Base64Url ile kodlanmış olsa da şifrelenmemiştir, bu nedenle kolayca okunabilir. Hassas kullanıcı verilerinin payload'a eklenmesi, token ele geçirildiğinde bu verilerin de ifşasına yol açar.

Algoritma değiştirme saldırıları (Algorithm Confusion Attacks) bir başka tehlikedir. Saldırgan, header'daki `alg` alanını `HS256` (simetrik) gibi güvenli bir algoritmadan `none`'a veya zayıf bir algoritmaya değiştirip, imza doğrulama mantığındaki bir zaafiyetten yararlanarak geçersiz bir token'ı geçerli gibi göstermeye çalışabilir. Bu nedenle, token doğrulama kütüphanenizin her zaman beklenen algoritmayı zorlaması (algorithm enforcement) çok önemlidir. Ayrıca, token'ın yeniden kullanılması (replay attack) riski de vardır. Aynı geçerli token'ın saldırgan tarafından tekrar tekrar sunucuya gönderilmesi, belirli işlemlerin tekrarlanmasına neden olabilir.

Bu riskleri azaltmak için çok katmanlı stratejiler benimsenmelidir. XSS'ten token çalınması riskini minimize etmek için, token'ları httpOnly, Secure ve SameSite=Strict özniteliklerine sahip cookie'lerde saklamak en etkili yöntemlerden biridir. Bu, tarayıcının JavaScript'in cookie'ye erişmesini engeller. Eğer Authorization header kullanılacaksa, XSS'e karşı çıktı kodlama ve içerik güvenlik politikaları (CSP) gibi diğer web güvenliği önlemleri sıkı bir şekilde uygulanmalıdır. Hassas veri sızıntısını önlemek için, JWT payload'ına asla şifre, özel kimlik numaraları veya finansal bilgiler gibi veriler eklenmemelidir. Yalnızca kimlik doğrulama ve yetkilendirme için gerekli minimum bilgi (user ID, rolleri) taşınmalıdır.

Algorithm confusion saldırılarına karşı, token doğrulama kodunuzun sadece belirli, güvenli algoritmaları (`RS256`, `ES256`, `HS256`) kabul etmesini ve header'daki `alg` değerini körü körüne güvenmemesini sağlamalısınız. Kütüphane yapılandırmasında doğrulama için kullanılan anahtarın, belirtilen algoritma ile tutarlı olması garanti edilmelidir. Replay saldırılarını önlemek için ise, kritik işlemlerde (örneğin, para transferi) `jti` (JWT ID) claim'i kullanılabilir ve sunucu tarafında kısa süreli bir kullanılmış token kimlikleri önbelleği tutulabilir. Daha basit ve etkili bir yöntem ise, access token ömrünü mümkün olduğunca kısa tutmaktır (örneğin 5-15 dakika). Bu, çalınan bir token'ın kullanılabileceği zaman penceresini dramatik şekilde daraltır. Kısa ömürlü access token'lar için, güvenli bir şekilde saklanan refresh token'lar ile yenileme mekanizması kurulmalıdır. Refresh token'ların çalınma riski daha düşüktür çünkü çok daha seyrek kullanılırlar ve güvenli cookie'lerde saklanabilirler.