Giriş ve Endüstriyel Motivasyon
Dağıtık mikroservis ekosistemlerinde, tek sayfa uygulamalarında (SPA - React, Vue) ve mobil platformlarda kimlik doğrulama (Authentication) ile yetkilendirme (Authorization) mekanizmalarını güvenle ayırmak kurumsal güvenliğin temel şartıdır. 2012 yılında yayınlanan orijinal OAuth 2.0 (RFC 6749) standardı, modern tek sayfa uygulamalarının ve mobil cihazların henüz yaygınlaşmadığı bir dönemde formüle edilmişti.
Geçtiğimiz yıllarda ortaya çıkan Authorization Code Injection, Token Theft ve Cross-Site Script Inclusion (XSSI) tehditleri; IETF çalışma grubunu OAuth 2.1 konsolide güvenlik standardını yayınlamaya yönlendirmiştir. OAuth 2.1, güvensiz pratikleri tamamen yürürlükten kaldırarak PKCE (Proof Key for Code Exchange) protokolünü tüm istemciler için zorunlu hale getirmiştir.

İçindekiler Tablosu
1. OAuth 2.0'dan OAuth 2.1'e Temel Mimari Değişiklikler
2. OAuth 2.1 vs OpenID Connect (OIDC): Yetkilendirme ve Kimlik Ayrımı
3. PKCE (RFC 7636) Nasıl Çalışır? Matematiksel Çözümleme
4. DPoP (Demonstrating Proof of Possession): Token Hırsızlığına Son
5. Üretim Standartlarında PKCE ve Token Doğrulama Akışı
6. Saldırı Senaryoları ve Savunma Karşılaştırması
7. Sıkça Sorulan Sorular (FAQ)
8. Sonuç ve Güvenlik Stratejileri
1. OAuth 2.0'dan OAuth 2.1'e Temel Mimari Değişiklikler
IETF tarafından hazırlanan resmi OAuth 2.1 Spesifikasyonu, son on yılda yayınlanan RFC 7636, RFC 8252, RFC 6819 ve RFC 8725 güvenlik standartlarını tek bir bağlayıcı dokümanda birleştirmiştir:
1. Implicit Grant Tamamen Kaldırıldı: Tarayıcı URL fragment'ında (#access_token=...) doğrudan token dönen Implicit akış, tarayıcı geçmişine ve yönlendirme başlıklarına sızdığı için OAuth 2.1'de tamamen yasaklanmıştır.
2. Resource Owner Password Credentials (ROPC) Kaldırıldı: Kullanıcı adı ve şifrenin doğrudan istemci uygulamaya verilmesi anti-pattern olarak kabul edilmiş ve standart dışı bırakılmıştır.
3. PKCE (Proof Key for Code Exchange) Zorunlu Kılındı: Artık yalnızca mobil ve SPA değil, sunucu taraflı güvenilir (Confidential) istemciler de Authorization Code akışında PKCE kullanmak zorundadır.
4. Tam URL Eşleşmesi (Exact Redirect URI Matching): Yönlendirme adreslerinde joker karakter () kullanımı yasaklanmış, protokol ve domain tam eşleşmesi zorunlu kılınmıştır.
[!WARNING]
Eski sistemlerde kullanılangrant_type=passwordveyaresponse_type=tokenyapılandırmaları modern güvenlik denetimlerinde (Penetration Test) doğrudan Kritik Zafiyet (Critical Finding) olarak raporlanmaktadır.
2. OAuth 2.1 vs OpenID Connect (OIDC): Yetkilendirme ve Kimlik Ayrımı
Yazılım geliştiriciler arasında en sık yapılan hata, OAuth ve OIDC kavramlarını birbirine karıştırmaktır:
OAuth 2.1 bir Yetkilendirme (Authorization) protokolüdür: "Bu istemci, kullanıcının adına fotoğraf yükleyebilir mi?" sorusuna yanıt verir. Kullanıcı kimliği hakkında bilgi vermez, yalnızca bir erişim izni (Access Token) üretir.
OpenID Connect (OIDC) bir Kimlik Doğrulama (Authentication) katmanıdır: OAuth 2.0/2.1'in üzerine inşa edilmiş bir kimlik protokolüdür. "Giriş yapan kullanıcının adı, e-postası ve benzersiz kimliği nedir?" sorusuna yanıt verir. İstemciye kriptografik olarak imzalanmış bir ID Token (JWT) teslim eder.
Platformumuzdaki Siber Güvenlik Rehberleri ve Zero Trust Prensipleri doğrultusunda, kimlik doğrulama için OIDC id_token, API isteklerini yetkilendirmek için ise OAuth 2.1 access_token kullanılmalıdır.
3. PKCE (RFC 7636) Nasıl Çalışır? Matematiksel Çözümleme
RFC 7636 ile tanımlanan PKCE (Proof Key for Code Exchange), yetkilendirme kodunun (Authorization Code) araya giren kötü niyetli bir uygulama veya zararlı yazılım tarafından çalınması durumunda bile token'a dönüştürülmesini imkansız kılar.

Mekanizma üç aşamadan oluşur:
1. Code Verifier Üretimi: İstemci, kriptografik olarak güvenli rastgele bir dizi üretir ($43-128$ karakter):
$$V \in \{A-Z, a-z, 0-9, -, ., _, ~\}^{128}$$
2. Code Challenge Hesaplanması: İstemci, verifier'ın SHA-256 özetini alır ve Base64URL formatında kodlar:
$$C = \text{Base64URL}(\text{SHA256}(V))$$
3. Doğrulama (Verification): İstemci yetki sunucusundan kod talep ederken yalnızca $C$'yi gönderir. Kod teslim alındığında ise token takası için orijinal $V$'yi gönderir. Yetki sunucusu şu eşitliği doğrular:
$$\text{Base64URL}(\text{SHA256}(V_{\text{gelen}})) \stackrel{?}{=} C_{\text{kayıtlı}}$$
Eğer saldırgan yetkilendirme kodunu (code) ele geçirse bile, istemcinin belleğinde saklanan $V$ değerini bilmediği için yetki sunucusundan Access Token alamaz.
4. DPoP (Demonstrating Proof of Possession): Token Hırsızlığına Son
Klasik Bearer Token mimarisinde, token'ı elinde tutan herkes ("Bearer") API'lara istek atabilir. Token çalındığı anda saldırgan meşru kullanıcı gibi davranabilir.
RFC 9449 ile standartlaşan DPoP (Demonstrating Proof of Possession), Access Token'ı istemcinin özel anahtarına (Private Key) kriptografik olarak kilitler:
İstemci tarayıcıda veya cihazda bir asimetrik anahtar çifti (Public/Private Key) üretir.
API'ye atılan her HTTP isteğine, o anki HTTP metodu ve URL'si özel anahtarla imzalanarak bir DPoP başlığı (JWT) olarak eklenir.
Token çalınsa bile, saldırgan istemcinin özel anahtarına sahip olamayacağı için çalınan token başka bir cihazdan kullanılamaz.
5. Üretim Standartlarında PKCE ve Token Doğrulama Akışı
Aşağıda, modern bir backend servisinde PKCE parametrelerinin doğrulanması ve yetkilendirme kodunun güvenle onaylanması için üretim düzeyinde PHP 8.4 kodu yer almaktadır:
<?php
declare(strict_types=1);
namespace Bilgiseli\Security\OAuth;
class PkceValidator
{
/**
* RFC 7636 Bölüm 4.6 uyarınca Code Challenge doğrulaması.
*/
public static function verify(
string $codeVerifier,
string $storedChallenge,
string $method = 'S256'
): bool {
// 1. Minimum ve maksimum karakter uzunluğu denetimi
$len = strlen($codeVerifier);
if ($len < 43 || $len > 128) {
return false;
}
// 2. Karakter kümesi denetimi (A-Z, a-z, 0-9, '-', '.', '_', '~')
if (!preg_match('/^[A-Za-z0-9\-._~]+$/', $codeVerifier)) {
return false;
}
// 3. S256 Algoritması ile Challenge Hesaplama
if ($method === 'S256') {
$computedHash = hash('sha256', $codeVerifier, true);
$computedChallenge = rtrim(strtr(base64_encode($computedHash), '+/', '-_'), '=');
// Zamanlama saldırılarına (Timing Attacks) karşı hash_equals kullanımı
return hash_equals($storedChallenge, $computedChallenge);
}
// OAuth 2.1 spesifikasyonunda 'plain' yöntemi önerilmez
return false;
}
}
// Örnek Test Doğrulaması:
$clientVerifier = 'dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk';
// S256(verifier) = 'E9Melhoa2OwvFrEMTJguCHaoeK1t8URWbuGJSstw-cM'
$storedChallenge = 'E9Melhoa2OwvFrEMTJguCHaoeK1t8URWbuGJSstw-cM';
$isValid = PkceValidator::verify($clientVerifier, $storedChallenge);
echo $isValid ? "PKCE Dogrulamasi Basarili: Token Basildi" : "Gecersiz Verifier: Erisim Reddedildi";
[!TIP]
String karşılaştırmalarında doğrudan===yerine daimahash_equals()fonksiyonu kullanılmalıdır. Bu pratik, saldırganların milisaniyelik yanıt gecikmelerinden anahtarları tahmin etmesini (Timing Attack) önler.
6. Saldırı Senaryoları ve Savunma Karşılaştırması
| Tehdit / Saldırı Türü | OAuth 2.0 (Eski Standart) | OAuth 2.1 + PKCE + DPoP |
|---|---|---|
| Auth Code Interception | ⚠️ Güvenliksiz SPA'larda çalınabilir | 🛡️ PKCE ile imkansız hale getirildi |
| Token Replay Attack | ❌ Bearer token her yerden kullanılabilir | 🛡️ DPoP anahtar eşleşmesiyle engellendi |
| XSS ile Token Hırsızlığı | ⚠️ LocalStorage'daki token çalınabilir | 🛡️ HttpOnly Cookie veya DPoP koruması |
| CSRF Login Attack | ⚠️ State parametresi ihmal edilirse açık | 🛡️ Zorunlu PKCE + State/Nonce kontrolü |
| Implicit Grant Sızıntısı | ❌ Referrer başlığında token sızabilir | 🛡️ Implicit Grant tamamen kaldırıldı |
Sıkça Sorulan Sorular (FAQ)
Sunucu taraflı (Confidential) istemcilerde Client Secret varken PKCE neden zorunlu oldu?
Çünkü Authorization Code, kullanıcının tarayıcısı üzerinden yönlendirme (HTTP 302) ile taşınır. Tarayıcı eklentileri veya cihazdaki kötü niyetli uygulamalar bu kodu araya girerek ele geçirebilir. PKCE, kodun yalnızca kodu ilk talep eden meşru oturum tarafından takas edilebilmesini temin eder.Mobil uygulamalarda Client Secret saklamak neden güvensizdir?
Mobil APK ve IPA paketleri tersine mühendislikle (Decompile) kolayca deşifre edilebilir. Uygulama içine gömülen tüm sabit sırlar saldırganlar tarafından elde edilebilir. Bu nedenle mobil uygulamalar "Public Client" kabul edilir ve PKCE kullanmak zorundadır.JWT Access Token süresi ne kadar olmalıdır?
En iyi güvenlik pratiği, Access Token ömrünü kısa (örneğin 5-15 dakika) tutmak ve yenileme için güvenliRefresh Token Rotation (RTR) mekanizması uygulamaktır.
DPoP ile mTLS (Mutual TLS) arasındaki fark nedir?
mTLS, istemci sertifikalarının işletim sistemi ve TLS katmanında yönetilmesini gerektirir ve yönetimi karmaşıktır. DPoP ise tamamen uygulama (HTTP) katmanında çalışır, standart JSON Web Signature (JWS) kullanır ve tarayıcı ortamlarında zahmetsizce uygulanabilir.Sonuç ve Güvenlik Stratejileri
OAuth 2.1, dağınık güvenlik yamalarını ve güvensiz mirası temizleyerek modern API'lar için sağlam bir temel inşa etmiştir. PKCE protokolünün her istemci türü için zorunlu hale gelmesi ve DPoP ile token sahipliğinin kanıtlanması, kurumsal sistemlerde veri güvenliğini en üst düzeye çıkarmaktadır.
Konu hakkında derinleşmek için Zero Trust Güvenlik Mimarisi ve API Savunması, Modern Yazılım Mimarisi ve Bilgiseli Güvenlik Standartları sayfalarımızı ziyaret edebilirsiniz.