Güvenli API Tasarımı: Kimlik Doğrulama, Rate Limiting ve Girdi Doğrulama
Bir API'nin işlevsel olarak "çalışması" ile "güvenli olması" farklı şeylerdir. Çoğu güvenlik olayı, karmaşık bir sıfırıncı gün açığından değil, tasarım aşamasında atlanan temel bir kontrolden (eksik kimlik doğrulama, sınırsız istek, güvenilmeyen veriye körü körüne güvenme) kaynaklanır. Bu yazıda üretime çıkmadan önce her API için gözden geçirilmesi gereken dört alanı ele alıyoruz.
Kimlik Doğrulama ve Yetkilendirme
Kimlik doğrulama ("sen kimsin?") ile yetkilendirme ("bu işlemi yapabilir misin?") ayrı katmanlardır ve ikisi de gereklidir. Modern API'lerde yaygın yaklaşım:
- OAuth2 / JWT: Kısa ömürlü (ör. 15 dakika) erişim token'ı + ayrı bir yenileme (refresh) token'ı kullanmak, çalınan bir token'ın etki süresini sınırlar.
- Scope tabanlı yetkilendirme: Bir token'ın yalnızca ihtiyaç duyduğu kaynaklara erişebilmesi ("read:orders" gibi), tüm API'ye tam erişim veren tek bir anahtardan çok daha güvenlidir.
- Sunucu tarafı yetki kontrolü: Yetki kontrolünü yalnızca istemci arayüzünde (ör. bir butonun gizlenmesi) yapmak yeterli değildir; her endpoint kendi içinde "bu kullanıcı bu kaynağa erişebilir mi" kontrolünü tekrar yapmalıdır (IDOR — Insecure Direct Object Reference açıklarının en sık nedeni budur).
Rate Limiting ve Kötüye Kullanım Önleme
Rate limiting olmayan bir API, hem kaba kuvvet (brute-force) saldırılarına hem de kaynak tüketme (DoS benzeri) senaryolarına açıktır. Yaygın ve etkili bir yöntem token bucket algoritmasıdır: her istemciye belirli bir kapasitede bir "kova" tanımlanır, her istek kovadan bir birim tüketir, kova zamanla yeniden dolar.
- Kimlik doğrulama uç noktalarında (login, parola sıfırlama) daha sıkı limit uygulanmalı — bunlar brute-force'un doğrudan hedefidir.
- Limit aşıldığında istemciye
429 Too Many Requestsyanıtı ve ne zaman tekrar deneyebileceğini belirten birRetry-Afterbaşlığı dönülmelidir. - Limitleme yalnızca IP bazlı değil, kimliklendirilmiş kullanıcı/API anahtarı bazlı da yapılmalıdır — paylaşımlı NAT arkasındaki meşru kullanıcıları cezalandırmamak için.
Girdi Doğrulama ve Çıktı Kodlama
"Gelen hiçbir veriye güvenme" ilkesi, API güvenliğinin belkemiğidir:
- Allow-list (izin listesi) doğrulama: Bir alanın hangi değerleri alabileceğini olumsuzlukla değil ("şunlar yasak") olumlu tanımla ("yalnızca şu formata/kümeye uyanlar kabul edilir").
- Parametreli sorgular: SQL enjeksiyonunu önlemenin tek güvenilir yolu, kullanıcı girdisini SQL metnine string birleştirmeyle değil, hazırlanmış ifadelere (prepared statement) parametre olarak vermektir.
- Çıktı kodlama: API bir yanıtı HTML içine yerleştirecek bir istemciye veri döndürüyorsa (ör. bir web arayüzü tarafından render edilecekse), XSS'i önlemek için çıktının bağlama uygun şekilde kodlanması istemci tarafının sorumluluğundadır — ama API, en azından hangi alanların "zengin metin" hangi alanların "düz metin" olduğunu açıkça belgelemelidir.
Hata Mesajları ve Bilgi Sızıntısı
Üretim ortamında bir API'nin döndürdüğü hata mesajı, saldırgana ücretsiz bir keşif raporu sunmamalıdır. Yığın izleri (stack trace), veritabanı sürücü hataları veya iç dosya yolları içeren ham hata mesajlarını istemciye döndürmek yerine, genel bir hata kodu + bir korelasyon kimliği (correlation id) döndürüp ayrıntıyı yalnızca sunucu taraflı günlüklerde tutmak hem güvenlik hem operasyonel izlenebilirlik açısından doğru yaklaşımdır.
Loglama ve İzlenebilirlik
Her isteğe bir korelasyon kimliği atamak, hem hata ayıklamayı hem güvenlik olayı incelemesini kolaylaştırır. Ancak loglama da bir güvenlik yüzeyidir: parola, token, kredi kartı gibi hassas alanlar loglara asla ham haliyle yazılmamalı; gerektiğinde maskelenmeli veya yalnızca türetilmiş bilgi (ör. "eşleşme var/yok", "uzunluk") kaydedilmelidir — ham istemci/sunucu çıktısının doğrudan loglanması, hata ayıklama sırasında farkında olmadan sır sızdırmanın en sık nedenlerinden biridir.