JWT hataları ve algoritma karışıklığı
- JWT doğrulamasındaki hataları test edersin: alg none tuzağı, RS256 ile HS256 karışıklığı ve kid başlık alanı enjeksiyonu.
- JWT üç bölümden oluşur ve gövdesi şifreli değildir, yalnız kodludur.
- En ağır hata, doğrulayacağı algoritmayı jetonun kendisinden okumaktır.
Puan bütün etkinlikleri cevaplayınca hesaba yazılır. Bu dersi tamamlayınca +55 XP alacaksın. Giriş yapmadan ilerlersen puan yalnız bu tarayıcıda durur.
JWT (JSON Web Token), iddiaları taşıyan imzalı bir jeton biçimidir ve çoğu uygulama onu oturum jetonu olarak kullanır. Sunucu, kim olduğunu her istekte yeniden sormak yerine sana imzalı bir jeton verir; sen de onu her istekte geri gösterirsin. Nokta ile ayrılmış üç bölümü vardır: başlık, gövde ve imza.
Başlık jetonun türünü ve imza algoritmasını taşır. Gövde iddiaları tutar: kim olduğun, jetonun ne zaman biteceği ve hangi role sahip olduğun.
Üçüncü bölüm imzadır ve ilk iki bölümün bütünlüğünü korur. Başlık ile gövde base64url ile kodlanır. Bu kodlama bir gizleme değildir; gövdeyi eline geçiren herkes onu geri açıp okur. RFC 7519 jetonun yapısını, RFC 7515 imza kurallarını tanımlar.
Üç parça, tek güvenlik
Kodlama ile şifreleme sık karıştırılır ve bu karışıklık ilk hataların kaynağıdır. Base64url yalnız baytları adres güvenli karakterlere çevirir; anahtar istemez, herkes geri çevirir. Yani gizlilik istiyorsan veriyi jetona koymazsın. Jetonun güvenliğini taşıyan tek şey imzadır.
Sunucu başlık ile gövdeyi kendi anahtarıyla imzalar ve gelen jetonu aynı anahtarla doğrular. İmza tutmuyorsa jeton sahtedir, reddedilir. Mekanizmanın kendisi sağlamdır; kırılan neredeyse hiçbir zaman matematik değil, doğrulama tarafındaki uygulamadır. Bu yüzden test kriptografiye değil, sunucunun imzayı nasıl kontrol ettiğine bakar.
Doğru soru şudur: bu jetonu kim, hangi anahtarla ve hangi algoritmayla doğruluyor? Bu üç sorunun cevabını görmeden jeton güvenliği hakkında yorum yazılmaz.
Etkinlik 1 / 7
Doğru mu, yanlış mı?
JWT gövdesini okumak için imza anahtarına ihtiyaç vardır.
Algoritmayı jetondan okumak
İmza doğrulamasının en kritik kararı, algoritmayı kimin belirlediğidir. Bazı kütüphaneler bu kararı jetonun kendi başlığındaki alg alanından okur. Böyle bir kütüphane kapıyı saldırgana teslim eder.
Standart, imzasız jetonlar için none değerini tanımlar. Doğrulayıcı bu değeri kabul ederse imza kontrolü tamamen atlanır ve gövde olduğu gibi doğru sayılır.
Sunucu algoritmayı kendi tarafında sabitlemezse, saldırgan başlığa none yazar ve imza bölümünü boş bırakarak sahte bir jeton üretir. Sonra gövdeye istediği rolü ekler ve yönetici gibi davranır. Algoritma seçimi hiçbir zaman istemci verisine bırakılmaz. Sunucu tek bir algoritmayı baştan kilitler ve gelen başlığa bakmadan onu uygular.
// Zafiyetli: algoritma jetondan okunur
const alg = JSON.parse(b64(token.split(".")[0])).alg;
jwt.verify(token, ANAHTAR, { algorithms: [alg] });
// Sağlam: algoritma sunucuda sabittir
jwt.verify(token, ACIK_ANAHTAR, { algorithms: ["RS256"] });Bazı sunucular none jetonlarını basit bir dizgi karşılaştırmasıyla eler. Saldırgan büyük küçük harf karışımıyla ya da beklenmedik bir yazımla bu süzgeci aşmayı dener; NoNe gibi bir yazım, katı olmayan bir kontrolü atlatabilir. Doğru savunma dizgi süzmek değil, kabul edilen algoritmayı sunucuda beyaz listeye almaktır.
Denetimin çalışıp çalışmadığını tek bir deneme gösterir. Elindeki geçerli jetonun imza baytlarını boz ve isteği tekrar yolla.
Bozuk imzalı jeton 401 dönüyorsa doğrulama iş görüyor. Aynı jeton 200 dönüyorsa imza hiç kontrol edilmiyordur. Bu iki denemeyi yapmadan jeton doğrulaması hakkında yorum yazılmaz; çünkü ekran görüntüsü değil, iki yanıt arasındaki fark kanıttır. Bulgu raporunda da bu iki yanıtı yan yana koyarsın.
$ echo eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9 | base64 -d
{"alg":"RS256","typ":"JWT"}
# Deneme 1: jeton olduğu gibi
GET /api/profil HTTP/1.1
Host: api.altaykargo.test
Authorization: Bearer <başlık>.<gövde>.<imza>
HTTP/1.1 200 OK
# Deneme 2: imzanın son dört karakteri değişti
GET /api/profil HTTP/1.1
Host: api.altaykargo.test
Authorization: Bearer <başlık>.<gövde>.<bozuk-imza>
HTTP/1.1 401 Unauthorized
{"hata":"invalid signature"}Örneği satır satır oku. İlk komut jetonun ilk bölümünü çözer. Çıktıdaki alg değeri RS256'dır, yani sunucu asimetrik bir imza bekliyor olmalı. typ alanı yalnız jetonun türünü söyler.
Birinci denemede jeton hiç değişmeden gider ve 200 döner; bu yanıt karşılaştırmanın temelidir. İkinci denemede başlık ve gövde aynı kalır, yalnız imzanın son dört karakteri değişir. Sunucu 401 ve imza hatasıyla yanıt veriyor, demek ki imzayı gerçekten doğruluyor. Aynı bozuk jetona 200 dönseydi, sunucu imzaya hiç bakmıyor olurdu ve bu tek başına kritik bir bulguydu.
Sıradaki kontrol alg alanını none yapıp imza bölümünü boşaltmaktır; sağlam bir sunucu bu jetona da 401 döner. Bunu yalnız kendi lab ortamında ya da yazılı iznin olan hedefte dene.
Etkinlik 2 / 7
Kütüphane doğrulamada algoritmayı jetonun başlığından okuyor. Saldırgan alg alanını none yaparsa ne olur?
Önce kodu oku, sonra çıktıyı seç.
jwt.decode(token, key, algorithms=jwt.get_unverified_header(token)["alg"])
Jetonu inceleme ve algoritma karışıklığı
İkinci klasik hata algoritma karışıklığıdır ve mantığını iki algoritma ailesini ayırınca kavrarsın. RS256 asimetriktir: özel anahtar imzalar, açık anahtar doğrular. Açık anahtar zaten herkese dağıtılır, gizli değildir. HS256 ise simetriktir: aynı anahtar hem imzalar hem doğrular ve gizli kalmalıdır.
Sunucu yalnız RS256 beklerken HS256 jetonlarını da kabul ederse tehlike doğar. Çünkü sunucu gelen jetonu HS256 sanıp elindeki açık anahtar metnini simetrik sır gibi kullanır. Oysa o açık anahtar herkeste vardır. İki aileyi ayrı anahtarlarla tutmak ve sunucuda tek aile kabul etmek bu karışıklığı kapatır.
Saldırının mantığı adım adım şudur. Saldırgan sunucunun açık anahtarını alır; bu değer zaten yayımlanır. Gövdeye yönetici rolünü yazar.
Jetonu HS256 ile, anahtar olarak o açık anahtarın metnini kullanarak imzalar. Başlıkta alg alanını HS256 yapar. Sunucu algoritmayı sabitlemediği için jetonu HS256 sanır, aynı açık anahtarla doğrular ve imzayı geçerli kabul eder.
Tek satırlık bir gövde değişikliği tam yetki yükseltmeye döner. Bu yüzden testin ilk adımı jetonu incelemektir: gövdeyi çözer, hangi alanların taşındığına bakarsın. Rol alanı gövdede açıkça duruyorsa, onu değiştirmek çoğu zaman en kısa yoldur.
Gövdeyi okumak için özel bir araç gerekmez, çünkü gövde yalnız kodludur. İkinci bölümü alıp base64url çözersin ve içindeki alanları düz metin olarak görürsün. Bu yüzden gövdeye gizli veri yazmak koruma vermez. Kimlik numarası, iç kullanıcı notu ya da bir anahtar oraya konmaz.
Gizlilik gerekiyorsa veri sunucuda kalır ve jeton yalnız ona işaret eden kısa bir kimlik taşır. Test sırasında gövdeyi çözmek, sunucunun hangi alanlara güvendiğini de açığa çıkarır. Rol, kiracı kimliği ya da yetki listesi gövdede duruyorsa, bu alanların değiştirilip değiştirilemediğini sınamak sıradaki adımdır ve çoğu zaman en verimli hamledir.
Etkinlik 3 / 7
Algoritma karışıklığına kapı açan satırı bul.
Şimdi bunu bir gövde üstünde uygula. Aşağıdaki dizgi bir JWT gövdesidir ve base64url ile kodlanmıştır. Onu çözdüğünde rol alanının değerini düz metin olarak okursun.
İşte bu kolaylık, jetona neden hiç gizli veri konmaması gerektiğini anlatır. Aynı çözme adımı, gerçek bir testin de ilk hamlesidir: eline geçen her jetonun gövdesini açar, hangi alanların taşındığını çıkarır ve bu alanların değiştirilip değiştirilemediğini tek tek denersin. Değeri değiştirip imzayı bozduğunda sunucu jetonu reddediyorsa doğrulama çalışıyordur; kabul ediyorsa gövdeye körü körüne güveniyordur ve bu bir bulgudur.
Etkinlik 4 / 7
Bu JWT gövdesini çöz ve rol alanının değerini yaz.
Araçları sırayla dene. Yanlış araç bozuk çıktı verir.
Başlık alanları ve karışıklığın etkisi
Karışıklığın sonucu ağırdır çünkü doğrulama anahtarı zaten saldırganın elindedir. Testte gerçek soru şudur: sunucu hangi algoritmaları kabul ediyor? İki jeton yollarsın, biri beklenen aile ile biri karışıklık denemesiyle, ve iki yanıtı karşılaştırırsın. Beklenmeyen ailenin de kabul edilmesi tek başına yüksek dereceli bir bulgudur.
Etkisini göstermek için de rol alanını değiştirdiğin gövdeyi ve sahte jetonun kabul edildiği yanıtı yan yana koyarsın. Savunma tek cümledir: sunucu beklediği tek algoritmayı kodda sabitler ve başka aileyi hiç denemez. Her algoritma için ayrı anahtar kullanmak da bu sınırı güçlendirir; böylece bir anahtar hem imzalama hem doğrulama sırrı olarak iki farklı ailede kullanılamaz.
Başlık yalnız algoritmayı taşımaz. Anahtar kimliği alanı, yani kid, hangi anahtarın kullanıldığını söyler. Doğrulayıcı bu değeri bir dosya yolu ya da veritabanı sorgusu olarak kullanırsa, oradan yol geçişi ve enjeksiyon doğar. Örneğin kid alanına boş bir aygıt dosyası yolu yazan saldırgan, sunucuyu boş bir dosyayı anahtar diye okumaya iter.
Boş sırla üretilen imza da geçerli sayılabilir. Aynı alan bir veritabanı sorgusuna gömülürse SQL enjeksiyonuna dönüşür. Doğru yaklaşım kid değerini sabit bir anahtar listesine eşlemek ve gelen veriyi arındırmaktır.
RFC 8725 tam olarak bunu, kid alanının SQL ya da LDAP enjeksiyonuna dönüşmemesini ister. jwk alanı ise doğrulama anahtarını jetonun içine gömer. Doğrulayıcı bu gömülü anahtara güvenirse, saldırgan kendi anahtar çiftiyle imzaladığı jetonu kabul ettirir. Bu yüzden doğrulayıcı gömülü anahtarı yok sayar ve yalnız kendi listesindeki anahtarı kullanır.
Savunma tarafında bu saldırıların hepsi kayıt bırakır ve tespit edilebilir. Doğrulayıcı, reddettiği her jetonu bir sebep koduyla kaydeder: algoritma uyumsuzluğu, süresi geçmiş jeton, tanınmayan yayıncı ya da eşleşmeyen anahtar kimliği.
Kısa bir süre içinde aynı hesaptan gelen çok sayıda reddedilmiş jeton, bir kurcalama denemesinin işaretidir ve bir alarma bağlanır. Aynı şekilde başlıktaki alg değerinin beklenenden farklı gelmesi ya da kid alanında yol karakterlerinin görünmesi, olay kaydında öne çıkarılır. Böylece test ederken bıraktığın izler savunma ekibinin de gördüğü izlerdir; iyi bir rapor, bulgunun yanında bu tespit fırsatını da gösterir.
Derinleş:Başlık enjeksiyonu: jku ve x5u
JWS başlığı, doğrulama anahtarına işaret eden alanlar da taşıyabilir. jku alanı bir JWK anahtar kümesinin adresini, x5u alanı bir sertifika zincirinin adresini gösterir. Doğrulayıcı bu adresi körü körüne çeker ve dönen anahtarla imzayı kontrol ederse iki sorun doğar. Birincisi anahtar sahteciliğidir: saldırgan kendi anahtar kümesini kendi sunucusunda yayımlar, jku alanını oraya çevirir ve jetonu o anahtarla imzalar.
İkincisi sunucu tarafı istek sahteciliğidir (SSRF): sunucu, saldırganın verdiği adrese istek atmaya zorlanır ve iç ağdaki bir hedefe uzanabilir. RFC 8725 bu adresleri izin verilen konumlar listesiyle eşleştirmeyi ve bu isteğe çerez eklememeyi önerir. Üretimde en güvenli seçim, anahtarları başlıktan hiç okumamak ve sunucuda sabit tutmaktır.
Etkinlik 5 / 7
RS256 bekleyen bir sunucuda HS256 karışıklığı nasıl sömürülür?
Doğrulamayı sağlamlaştırma
Doğru algoritma tek başına yetmez. exp süresi denetlenmezse jeton ömür boyu geçerli kalır ve çalınan tek jeton yıllarca kullanılır. Kullanıcının parolayı değiştirmesi bile bu jetonu durdurmaz. iss yayıncısı ve aud hedef kitlesi de her istekte kontrol edilir.
aud alanı, bir sağlayıcının ürettiği jetonun başka bir servise sokulmasını engeller. OWASP Top 10:2025 listesinde kimlik doğrulama hataları yedinci sırada durur ve JWT için tam da aud ile iss iddialarının ve kapsamların doğrulanmasını ister. Bu üç alanı denetlemeyen bir doğrulama, imza doğru olsa bile eksik kalır. Testte her alanı ayrı ayrı bozar, sunucunun hangisini gerçekten kontrol ettiğini yanıt farkından okursun.
Anahtar deponun içinde değil, ortam değişkeninde ya da bir sır yönetim aracında durur. Jetonu kendi elinle çözüp doğrulamak yerine olgun bir kütüphane kullanır ve onu güncel tutarsın; bu alandaki tarihi hataların çoğu eski sürümlerde kapanmıştır. Kütüphanenin çözme ve doğrulama işlevlerini karıştırmamak da önemlidir.
Çözme işlevi jetonu yalnız açar, imzayı kontrol etmez. Doğrulama işlevi ise imzayı ve algoritmayı sınar. Yanlış işlevi çağırmak, hiç doğrulamamakla aynı kapıya çıkar. Simetrik anahtar kullanıyorsan, anahtar en az kullandığın karma çıktısı kadar uzun olmalı; kısa ve tahmin edilebilir bir sır sözlük saldırısıyla kırılır ve bilinen zayıf sırlar hazır listelerle denenir.
JWT durumsuzdur, sunucu onu kendiliğinden geçersiz kılamaz. Ölçeklenmesi kolaydır ama iptali zordur; bu ödünleşim testin yönünü belirler. Süre kısa tutulur ve gerektiğinde kara liste ya da bir sürüm alanı ile iptal yolu açılır. Jetonun taşındığı yer de riski belirler.
Tarayıcı yerel deposunda duran jeton bir XSS ile dışarı taşınır. HttpOnly çerezde duran jeton betikten okunamaz ama siteler arası istek sahteciliğine karşı ek önlem ister. Bulguyu yazarken hem sahte jetonu hem sunucunun onu kabul ettiği yanıtı eklersin; iki kanıt yan yana durunca itiraz kalmaz.
Etkinlik 6 / 7
Elindeki jetonun gövde bölümünü komut satırında çöz. Gövde ikinci bölümdür.
Etkinlik 7 / 7
Hangi önlemler JWT doğrulamasını sağlamlaştırır?
Derinleş:2015: kütüphaneleri sarsan iki hata
JWT saldırılarının bilinir olması 2015'e dayanır. Güvenlik araştırmacısı Tim McLean, yaygın kütüphanelerin iki hatasını gösterdi. Birincisi none algoritmasını sessizce kabul etmekti; ikincisi RS256 bekleyen bir doğrulayıcıya HS256 jetonu yollayıp açık anahtarı HMAC sırrı olarak kullandırmaktı. Bu ikinci hata CVE-2015-9235 numarasıyla kayıtlara girdi ve node-jsonwebtoken kütüphanesinin 4.2.2 sürümünde kapatıldı; aynı sınıf hata PyJWT ve php-jwt gibi birçok kütüphanede de düzeltildi.
Çıkarılan ders kalıcı oldu: doğrulama işlevi kabul edilecek algoritmayı çağıran taraftan almalı, jetonun kendi başlığından değil. RFC 8725 bu çıkarımı 2020 Şubat'ında resmî en iyi uygulama olarak yazıya döktü. Bugün olgun bir kütüphanenin güncel sürümü bu tuzakları öntanımlı olarak kapatır ve none değerini ancak açıkça izin verilirse işler.
Okumayı istediğin sırayla sürdürebilirsin. Ders, bütün etkinlikleri cevapladığında tamamlanır.
- Etkinlik 1· Üç parça, tek güvenlik
- Etkinlik 2· Algoritmayı jetondan okumak
- Etkinlik 3· Jetonu inceleme ve algoritma karışıklığı
- Etkinlik 4· Jetonu inceleme ve algoritma karışıklığı
- Etkinlik 5· Başlık alanları ve karışıklığın etkisi
- Etkinlik 6· Doğrulamayı sağlamlaştırma
- Etkinlik 7· Doğrulamayı sağlamlaştırma