JSON Web Token (JWT) ile API Güvenliği: Kurulum Rehberi
JSON Web Token (JWT) ile API Güvenliği: Kurulum Rehberi
Giriş
Modern web uygulamaları ve mikroservis mimarilerinde API’ler, istemci ile sunucu arasında veri alışverişinin omurgasını oluşturur. Bu arayüzlerin güvenliğini sağlamak, yetkisiz erişimlerin önüne geçmek için kritik öneme sahiptir. Geleneksel oturum tabanlı kimlik doğrulama yöntemleri, dağıtık sistemlerde ölçeklenebilirlik ve durum yönetimi problemleri yaratırken; JSON Web Token (JWT) tabanlı yaklaşım, stateless yapısıyla hem performans hem de basitlik sunar. Bu rehberde, JWT’nin ne olduğunu, yapısını, kullanım senaryolarını, adım adım kurulumunu ve uygulamalarda entegrasyonunu ele alacak; token yönetimi, yenileme ve güvenlik önlemleri üzerine detaylı öneriler paylaşacağız.
1. JWT Nedir ve Neden Tercih Edilir?
JSON Web Token, RFC 7519 standardı çerçevesinde tanımlanmış, içeriğinde kullanıcı bilgileri ve ek meta veriler barındıran imzalı bir JSON yapısıdır. Sunucu, başarılı bir kimlik doğrulama sonrası bu token’ı oluşturur; istemci her API isteğinde, Authorization başlığında bearer token formatında sunucuya iletir. Sunucu, imzayı doğrulayarak token’ın bütünlüğünü ve geçerliliğini kontrol eder. JWT:
- Stateless (Durumsuz) bir yöntem olduğundan sunucuda oturum bilgisi saklamaz,
- Performans açısından veritabanı veya cache sorgusu gerektirmez,
- Esnek yapısıyla özel alanlar (claims) eklenip her uygulamaya uyarlanabilir,
- Çapraz dil ve platform desteği sunar (JavaScript, Python, Java, Go, .NET vb.).
Bu özellikler, mikroservisler arası haberleşmede ve mobil uygulamalarla entegrasyon senaryolarında JWT’yi ideal kılar.
2. JWT Yapısı ve Bileşenleri
Her JWT üç parçadan oluşur; nokta (.) ile ayrılmış bu bölümler Base64URL formatında kodlanır:
- Header (Başlık): Token tipini (typ: “JWT”) ve kullanılan imza algoritmasını (alg, örn. HS256, RS256) belirtir.
- Payload (Yük): Kullanıcı kimliği (sub), token’ın oluşturulma zamanı (iat), geçerlilik süresi (exp) ve uygulamaya özel ek veri (örneğin role, tenantId) gibi claim’leri içerir.
- Signature (İmza): Header ve payload bölümlerinin gizli bir anahtar veya özel anahtar ile HMAC veya RSA/ECDSA algoritmaları kullanılarak imzalanmasıyla üretilir.
Örnek bir token:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9
.
eyJzdWIiOiIxMjM0NTYiLCJuYW1lIjoiSmFuZSBEb2UiLCJyb2xlIjoiYWRtaW4iLCJleHAiOjE2MzAwMDAwMDB9
.
HMACSHA256(base64UrlEncode(header) + “.” + base64UrlEncode(payload), secret)
3. Kullanım Senaryoları
- RESTful API Güvenliği: Sunucu tarafında stateless oturum yönetimi, yüksek trafikli servisler için ideal.
- Mikroservis Haberleşmesi: Servisler arası talep doğrulaması ve rol tabanlı erişim kontrolleri.
- Mobil ve Tek Sayfa Uygulamalar (SPA): Tarayıcı veya mobil istemcide saklanan token sayesinde CORS sorunları minimuma iner.
- Third-Party Entegrasyonlar: Webhook, partner API erişimleri gibi senaryolarda token tabanlı geçici erişim imkânı.
4. Kurulum Adımları: Genel Hazırlık
JWT tabanlı güvenlik katmanını uygulamak için:
- Güvenli Anahtar Yönetimi: HMAC algoritması kullanacaksanız uygulamanın konfigürasyonunda gizli (secret) değerini saklayın. RSA veya ECDSA imzaları tercih ediyorsanız özel anahtar (private key) ve açık anahtar (public key) çiftinizi oluşturun; özel anahtarı asla paylaşıma açmayın.
- Kütüphane Seçimi: Kullandığınız platforma uygun, aktif olarak bakım gören JWT kütüphanelerini tercih edin (örn. JavaScript için jsonwebtoken, Python için PyJWT, Java için jjwt veya nimbus-jose-jwt).
- Zaman Senkronizasyonu: Token geçerlilik süreleri (exp) hassastır; sunucu saatinin NTP ile güncel olduğundan emin olun.
- Güvenlik Politikaları: Token boyutu, içerdiği veri miktarı, refresh mekanizmaları, imza algoritması seçimi gibi konulara karar verin. Genellikle HS256 yerine RS256 veya ES256 gibi asimetrik algoritmalar önerilir.
5. Uygulamada JWT Oluşturma ve Doğrulama
Node.js Örneği (Express + jsonwebtoken)
const jwt = require(“jsonwebtoken”);
const fs = require(“fs”);
// Asimetrik imza için
const privateKey = fs.readFileSync(“private.key”);
const publicKey = fs.readFileSync(“public.key”);
// Token oluşturma
function generateToken(user) {
const payload = {
sub: user.id,
name: user.username,
role: user.role,
};
return jwt.sign(payload, privateKey, {
algorithm: “RS256”,
expiresIn: “2h”,
issuer: “my-api”,
});
}
// Token doğrulama middleware’i
function authenticate(req, res, next) {
const authHeader = req.headers.authorization;
if (!authHeader) return res.sendStatus(401);
const token = authHeader.split(” “)[1];
jwt.verify(token, publicKey, { algorithms: [“RS256”], issuer: “my-api” }, (err, decoded) => {
if (err) return res.sendStatus(403);
req.user = decoded;
next();
});
}
Python Örneği (Flask + PyJWT)
import jwt
from datetime import datetime, timedelta
from flask import request, jsonify
PRIVATE_KEY = open(“private.pem”).read()
PUBLIC_KEY = open(“public.pem”).read()
def generate_token(user_id):
payload = {
“sub”: user_id,
“iat”: datetime.utcnow(),
“exp”: datetime.utcnow() + timedelta(hours=2)
}
return jwt.encode(payload, PRIVATE_KEY, algorithm=”RS256″)
def authenticate(f):
def wrapper(*args, **kwargs):
auth = request.headers.get(“Authorization”, None)
if not auth: return jsonify({“msg”: “Missing token”}), 401
token = auth.split()[1]
try:
decoded = jwt.decode(token, PUBLIC_KEY, algorithms=[“RS256”])
except jwt.ExpiredSignatureError:
return jsonify({“msg”: “Token expired”}), 401
except jwt.InvalidTokenError:
return jsonify({“msg”: “Invalid token”}), 403
request.user = decoded[“sub”]
return f(*args, **kwargs)
return wrapper
Java Örneği (Spring Boot + jjwt)
KeyPair keyPair = Keys.keyPairFor(SignatureAlgorithm.RS256);
String createToken(String userId) {
return Jwts.builder()
.setSubject(userId)
.setIssuedAt(Date.from(Instant.now()))
.setExpiration(Date.from(Instant.now().plus(2, ChronoUnit.HOURS)))
.setIssuer(“my-api”)
.signWith(keyPair.getPrivate())
.compact();
}
Claims validateToken(String token) {
return Jwts.parserBuilder()
.setSigningKey(keyPair.getPublic())
.requireIssuer(“my-api”)
.build()
.parseClaimsJws(token)
.getBody();
}
6. Token Yaşam Döngüsü ve Yenileme
- Access Token: Kısa ömürlü (15m–2h) ve sık doğrulanan token.
- Refresh Token: Uzun ömürlü (7–30 gün) token; access token’ın süresi dolunca yeni bir access token oluşturmak için kullanılır. Refresh token’lar veritabanında veya güvenli saklama alanında tutulmalı; her kullanımda geçersizleştirilecek şekilde dizayn edilmelidir.
- Token Revocation: Blacklist (kara liste) sistemleri, özellikle refresh token’lar iptal edildiğinde hesabın bütün aktif token’larını geçersiz kılmak için gereklidir.
7. Güvenlik Önlemleri
- Asimetrik İmzalar: HMAC’a kıyasla özel/halka açık anahtar yapısı, secret’ın istemci tarafına sızmasını engeller.
- exp ve iat Claim’leri: Token’ın geçerlilik süresini ve oluşturulma zamanını zorunlu tutun.
- aud ve iss: Hedef API ve token düzenleyiciyi doğrulamak için audience ve issuer claim’lerini kullanın.
- JTI (JWT ID): Her token’a benzersiz bir ID atayıp, tekrar kullanım veya replay ataklarına karşı önlem alın.
- CORS ve Secure Cookie Politikaları: Token’ı HTTP-only, Secure ve SameSite cookie olarak iletmek, XSS riskini azaltır. Alternatif olarak localStorage yerine Authorization başlığını tercih edin.
- Algoritma Sabitleme: Sunucu tarafında sadece izin verdiğiniz algoritmaları (RS256 gibi) kabul edin, alg: none saldırılarına karşı önlem alın.
8. Performans ve Ölçeklendirme
- Stateless Doğrulama: Her istekte imza kontrolü yapılır; bu işlem kriptografik maliyet doğurduğundan, yüksek trafikte CPU kullanımı artabilir. GPU hızlandırma veya daha hafif algoritmalar (ES256) tercih edin.
- Cache Layer: Sunucu tarafı doğrulama sonuçlarını kısa süreli önbelleğe alarak (örn. Redis TTL ile), aynı token için tekrarlı imza doğrulamasını azaltabilirsiniz.
- Token Boyutu: Payload’a gereksiz veri eklemekten kaçının; token’ı minimal bilgileri taşıyacak şekilde tasarlayın.
9. İzleme ve Log Yönetimi
- Başarılı/başarısız doğrulama sayıları,
- Expired token hataları,
- Blacklist kullanımı ve token iptal oranı,
gibi metrikler izlenerek API güvenlik durumu değerlendirilebilir. ELK, Prometheus veya managed log servisleri ile bu verileri toplayıp dashboard oluşturarak, anormalliklere hızla müdahale edebilirsiniz.
10. En İyi Uygulamalar
- Minimal Yetki (Least Privilege): Token içindeki claim’lerde sadece gerekli bilgileri tutun, rolleri net şekilde ayırın.
- Sürekli Anahtar Rotasyonu: Belirli dönemlerde yeni anahtar çifti oluşturun, eski anahtarlar için grace period tanıyıp rotasyon yapın.
- Rate Limiting: API uç noktalarınızı korumak için token kullanımı bazlı hız sınırlayıcı (rate limiting) kuralları uygulayın.
- Penetrasyon Testi ve Güvenlik Tarama: JWT implementasyonunuzu düzenli olarak OWASP ZAP, Burp Suite gibi araçlarla test edin.
- Dokümantasyon: Token formatı, claim listesi ve yenileme akışını API dokümantasyonunuzda açıkça belirtin.
Sonuç
JSON Web Token tabanlı API güvenliği, stateless mimarisi, platform bağımsızlığı ve performans avantajları ile modern uygulamaların vazgeçilmezi haline geliyor. Doğru imza algoritması seçimi, yaşam döngüsü yönetimi, token yenileme stratejileri ve güçlü keamanan önlemleri uygulandığında, hem geliştirici deneyimi hem de servis güvenilirliği üst seviyelere taşınabilir. Bu rehberde paylaşılan adımları takip ederek, JWT’yi altyapınıza entegre edebilir, API’lerinizde hem ölçeklenebilir hem de dayanıklı bir kimlik doğrulama katmanı oluşturabilirsiniz.