Merhaba, önceki derslerimizde bir kimlik doğrulama akışının farklı aşamalarına odaklandık: önce JWT'nin kendi içindeki kriptografik zayıflıkları, ardından bu token'ların elde edildiği OAuth/OIDC protokollerindeki mantık hatalarını inceledik. Artık elimizde geçerli bir access ve refresh token var. Bu derste, bu token'ların modern, dağıtık mimarilerde nasıl tehlikeli ve tespiti zor yeni zafiyetlere yol açabileceğini analiz edeceğiz.
Bu dersin sonunda, dağıtık sistemlerdeki iki karmaşık oturum yönetimi başarısızlık modunu kod seviyesinde tespit etme becerisi kazanacaksınız: hizmetler arası oturum karışıklığı (cross-service session confusion) ve token yenileme mekanizmalarındaki yarış koşulları (token renewal race conditions). Bu zafiyetler, monolitik uygulamalarda pek görülmeyen, ancak mikroservis mimarilerinin doğasından kaynaklanan ve genellikle otomatize araçların kavrayamadığı, ileri seviye mantık hatalarıdır.
Dağıtık Mimaride Oturum Yönetiminin Haritası
Mikroservis tabanlı bir sistemde oturum yönetimi, monolitik bir uygulamadan çok daha karmaşıktır. Genellikle merkezi bir kimlik doğrulama (authentication) ve yetkilendirme (authorization) akışı kullanılır. Aşağıdaki diyagram, bu tür bir mimarideki temel aktörleri ve akışı özetlemektedir.

Bu mimariyi analiz ederken şu noktaları aklımızda tutmalıyız:
- API Gateway: Gelen tüm istekleri karşılayan, genellikle JWT'nin imzasını ve geçerliliğini doğrulayan ilk savunma hattıdır.
- Identity Provider (Auth Server): Kullanıcı kimliğini doğrulayan, Access Token (JWT) ve Refresh Token üreten merkezi otoritedir.
- Microservices (Service X): Kendi iş mantığını yürüten servislerdir. API Gateway'den geçen isteği aldıktan sonra, genellikle JWT'nin içindeki
claim'leri (kullanıcı ID'si, roller, kapsam vb.) okuyarak yetkilendirme kararlarını verirler. - Refresh Token Akışı (Adım 9-11): Access Token'ın (JWT) süresi dolduğunda, istemci Refresh Token'ı kullanarak kimlik sağlayıcıdan yeni bir Access Token talep eder. Bu akış, dersimizin ikinci bölümünde odaklanacağımız yarış koşulları için kritik bir alandır.
Bu dağıtık güven modelindeki temel varsayım, tüm servislerin aynı token'ı anlaması ve ona güvenmesidir. Ancak bu güven, "oturum karışıklığı" ve "yarış koşulları" gibi incelikli hatalara zemin hazırlar.
1. Çapraz Hizmet Oturum Karışıklığı (Cross-Service Session Confusion)
Bu zafiyet, bir bağlamda (veya bir hizmet için) üretilmiş bir token'ın, farklı bir bağlamda (veya farklı bir hizmette) kötüye kullanılmasıyla ortaya çıkar. JWT bir "bearer token" olduğu için, onu elinde bulunduran kişi, token'ın izin verdiği tüm yetkilere sahip olur. Eğer bir mikroservis, kendisine sunulan bir JWT'yi doğrulamak için yeterince katı kontroller yapmazsa, başka bir hizmet için tasarlanmış bir token'ı kabul edebilir.
Aşağıdaki diyagram, bir saldırganın çaldığı bir token'ı farklı hizmetlere karşı kullanarak nasıl bir istismar zinciri oluşturabileceğini göstermektedir.

Kod Analizinde Aranacak Kırmızı Bayraklar
Güvenli kod analizi yaparken, her mikroservisin gelen JWT'yi nasıl işlediğine dair şu soruları sormalısınız:
-
Audience (
aud) Claim'i Doğrulanıyor mu?
Bir JWT'ninaudclaim'i, o token'ın hangi hizmet veya hizmetler ("audience") için üretildiğini belirtir. Örneğin,aud: ["user-profile-service", "billing-service"]. Eğerbilling-service, kendisine gelen bir token'ınaudclaim'inde kendi adının geçtiğini kontrol etmezse, sadeceuser-profile-serviceiçin üretilmiş bir token'ı yanlışlıkla kabul edebilir. Bu, özellikle hassas işlemleri gerçekleştiren servisler için kritik bir kontroldür. Kodda bu claim'in atlandığı veya yanlış doğrulandığı yerleri arayın. -
Scope (
scp) ve Yetki Claim'leri Yeterince Kontrol Ediliyor mu?
Bir token,scope: "read:profile write:profile"gibi yetkileri içerebilir. Bir servis içindeki farklı endpoint'ler bu scope'ları farklı şekilde yorumlayabilir. Tehlikeli bir desen, bir servisin bazı endpoint'lerinin sadece token'ın geçerli bir imzaya sahip olup olmadığını kontrol edip, belirli bir işlem için gerekli olanscope'un varlığını kontrol etmeyi unutmasıdır. Örneğin,/api/users/meendpoint'iread:profilescope'unu kontrol ederken,/api/admin/delete_all_usersendpoint'i sadece geçerli bir token bekliyor olabilir. Bu, klasik bir yetkilendirme atlatma mantık hatasıdır. -
Issuer (
iss) Claim'i Doğrulanıyor mu?issclaim'i, token'ı kimin ("issuer") ürettiğini belirtir. Bu, sistemde birden fazla kimlik sağlayıcı varsa veya gelecekte eklenmesi planlanıyorsa özellikle önemlidir. Her servis, sadece güvendiğiissuer'lardan gelen token'ları kabul ettiğinden emin olmalıdır. -
API Gateway'e Körü Körüne Güveniliyor mu?
Yaygın bir mimari deseni, API Gateway'in JWT'yi doğrulayıp, kullanıcı bilgilerini (X-User-ID,X-Rolesgibi) HTTP başlıkları (header) ile aşağı akış servislerine (downstream microservices) iletmesidir. Mikroservisler de bu başlıklara güvenerek kendi iş mantığını yürütür. Eğer bir mikroservis yanlışlıkla doğrudan internete açılırsa (örneğin bir konfigürasyon hatasıyla), saldırgan API Gateway'i atlayarak bu başlıkları taklit edebilir ve kendini farklı bir kullanıcı veya admin olarak tanıtabilir. Kodda, bu tür başlıklara güvenen ancak bir token'ın varlığını veya geçerliliğini tekrar kontrol etmeyen noktalar kritik zafiyetlerdir. Bu durum, önceki derslerde ele aldığımız "Kullanıcı IP’sinden Bağımsız Oturum Oluşturma Açığı"nın modern bir tezahürüdür; burada IP yerine güvenilir bir giriş noktası (gateway) varsayımı ihlal edilmektedir.
2. Token Yenileme Yarış Koşulları (Token Renewal Race Conditions)
Yarış koşulları (Race Conditions), bir sistemin çıktısının, kontrol dışı olayların sıralamasına veya zamanlamasına bağlı olduğu durumlarda ortaya çıkan hatalardır. Oturum yönetimi bağlamında bu zafiyet, genellikle Refresh Token'ların kullanıldığı token yenileme sürecinde kendini gösterir. Bu, klasik bir "Time-of-Check to Time-of-Use" (TOCTOU) problemidir.
A.I. ve MCP Dünyasında Race Condition Güvenlik Açıkları Büyük Risk Yaratacak.
Konunun teorik temelini anlamak için, Mehmet İnce'nin bu videosu yarış koşullarının ve TOCTOU zafiyetlerinin arkasındaki temel mantığı mükemmel bir şekilde açıklıyor.
Lütfen videonun TOCTOU tanımını yapan bölümünü izleyin. "Bir işlemi yapabilme yetkinizin olup olmadığını kontrol etmek ile o işlemi yapmak arasındaki geçen süre" ifadesi, token yenileme senaryosunun temelini oluşturur. Ardından, dosya izni kontrolü ve yazma işlemi örneğini dinleyin. Bu, "Refresh Token'ı kontrol et" (Check Permission) ve "Yeni token'ları üret/eskiyi geçersiz kıl" (Write File) adımları arasındaki boşluğun nasıl istismar edilebileceğine dair harika bir analogidir.
Şimdi bu TOCTOU prensibini Refresh Token akışına uygulayalım:
Saldırı Senaryosu:
Güvenli bir Refresh Token implementasyonunda, bir Refresh Token kullanıldığında derhal geçersiz kılınmalı ve yerine yenisi üretilmelidir (Refresh Token Rotation). Bu, çalınan bir Refresh Token'ın tekrar tekrar kullanılmasını engeller. Ancak, bu "kullan ve geçersiz kıl" operasyonu atomik değilse, bir yarış durumu ortaya çıkabilir.
- Hazırlık: Saldırgan, bir şekilde kurbanın geçerli Refresh Token'ını ele geçirir (örneğin, kurbanın cihazındaki bir zafiyet veya XSS ile).
- Yarış Başlangıcı: Kurbanın uygulaması, Access Token'ı süresi dolduğu için, ele geçirilen bu Refresh Token ile
/auth/refreshendpoint'ine bir istek (İstek A) gönderir. - Paralel İstek: Saldırgan, aynı anda, aynı Refresh Token ile
/auth/refreshendpoint'ine kendi isteğini (İstek B) gönderir. - Zamanlama Penceresi (TOCTOU):
- Sunucu, İstek A'yı alır ve veritabanında Refresh Token'ın geçerli olup olmadığını kontrol eder (Time-of-Check). Token geçerlidir.
- Sunucu, İstek A'yı işlemeye devam ederken, thread'ler arası geçiş veya ağ gecikmesi nedeniyle, İstek B'yi de alır ve onun da Refresh Token'ını kontrol eder (Time-of-Check). Token, İstek A tarafından henüz geçersiz kılınmadığı için hâlâ geçerlidir.
- Sunucu, İstek A için yeni bir Access Token ve yeni bir Refresh Token üretir, eski Refresh Token'ı veritabanında geçersiz olarak işaretler ve yanıtı kurbana gönderir (Time-of-Use).
- Sunucu, İstek B'yi işlemeye devam eder. Kontrol adımını zaten geçtiği için, o da yeni bir Access Token ve yeni bir Refresh Token üretir ve yanıtı saldırgana gönderir (Time-of-Use).
Sonuç? Hem kurban hem de saldırgan, geçerli birer oturuma (Access + Refresh Token çifti) sahip olur. Saldırgan, kurbanın oturumunu tamamen ele geçirmiş olur.
Kod Analizinde Aranacak Kırmızı Bayraklar
-
Atomik Olmayan Operasyonlar: Refresh Token yenileme mantığının kodunu incelerken, "token'ı bul", "geçerli mi diye kontrol et", "geçersiz olarak işaretle" ve "yeni token'ları kaydet" adımlarının tek bir atomik işlem (atomic transaction) içinde olup olmadığına bakın. Eğer bu adımlar ayrı ayrı veritabanı sorguları ile yapılıyorsa ve arada bir kilitleme mekanizması (örneğin SQL'de
SELECT ... FOR UPDATE) kullanılmıyorsa, sistem yarış koşullarına karşı savunmasızdır. -
Refresh Token Rotasyonu Eksikliği: Kod, bir Refresh Token kullanıldıktan sonra onu geçersiz kılıp yerine yenisini üretiyor mu? Eğer aynı Refresh Token birden çok kez kullanılabiliyorsa, bu durum yarış koşulu riskini ortadan kaldırsa bile çalınması durumunda çok daha büyük bir risk oluşturur. Bu, kendi başına kritik bir zafiyettir.
-
Yeniden Kullanım Tespiti (Reuse Detection) Eksikliği: En güvenli implementasyonlar, bir Refresh Token kullanıldığında onu sadece geçersiz kılmakla kalmaz, aynı zamanda bir "aile" (family) içindeki tüm token'ları geçersiz kılar. Eğer daha önce kullanılmış bir Refresh Token tekrar sunulursa, bu bir sızıntı işareti olarak kabul edilir ve o kullanıcıya ait tüm aktif Refresh Token'lar iptal edilir. Kodda, kullanılan token'ları bir "denylist" veya "revocation list" üzerinde kısa bir süre tutarak yeniden kullanımı tespit eden bir mekanizmanın olmaması önemli bir eksikliktir.
Sonuç
Dağıtık mimariler, ölçeklenebilirlik ve esneklik gibi avantajlar sunsa da, güvenlik açısından yeni ve karmaşık zorluklar ortaya çıkarır. Bu derste incelediğimiz çapraz hizmet oturum karışıklığı ve token yenileme yarış koşulları, bu zorlukların en somut örneklerindendir. Bu tür zafiyetler, basit bir imza doğrulamasının ötesine geçerek, servisler arası güven ilişkilerini ve eşzamanlılık (concurrency) mantığını derinlemesine anlamayı gerektirir.
Temel Çıkarımlar:
- Asla Güvenme, Her Zaman Doğrula (Zero Trust): Bir mikroservis, API Gateway'den veya başka bir servisten geldiği varsayımıyla hiçbir bilgiye körü körüne güvenmemelidir. Gelen her JWT'nin
aud,iss,scpgibi kritikclaim'leri, o servisin kendi bağlamı içinde titizlikle doğrulanmalıdır. - Atomiklik Kraldır: Eşzamanlılığın olduğu her yerde, özellikle de "kontrol et ve sonra kullan" desenlerinde, operasyonların atomik olduğundan emin olun. Veritabanı seviyesinde kilitler veya işlemler, yarış koşullarına karşı en güçlü savunmanızdır.
- Token Yaşam Döngüsünü Yönetin: Refresh Token'lar güçlü ama tehlikeli araçlardır. Tek kullanımlık olmalarını (rotation) ve yeniden kullanım denemelerinin tespit edilmesini (reuse detection) sağlayan bir strateji, oturum güvenliğinin temel direğidir.
Önceki derslerde token'ların nasıl elde edildiğini, bu derste ise elde edilen token'larla oturumların nasıl yönetildiğini ve istismar edilebildiğini gördük. Bir sonraki dersimizde, "Yetkilendirme ve Erişim Kontrolü" dünyasına daha da derin bir dalış yapacağız. Artık kimliği doğrulanmış ve geçerli bir oturuma sahip olan kullanıcının, uygulama içinde neler yapabileceğini belirleyen mekanizmaları inceleyeceğiz. Özellikle Express, Django ve Spring gibi modern framework'lerde middleware zincirleri, dekoratörler ve annotation'lar aracılığıyla yetkilendirmenin nasıl uygulandığını ve bu desenlerdeki gizli mantık hatalarını nasıl tespit edeceğimizi öğreneceğiz.