HG PHP GüvenliğiEl Kitabı
Bölümler 24 / 38

İçindekiler/API ve Modern Servis Güvenliği

Bölüm 24

OAuth 2.0 / OIDC Security

16 dk okuma3.283 kelimePHP 8.1+
Ön koşul

Bölüm 12 (kimlik doğrulama), Bölüm 17 (CSRF/state), Bölüm 20 (redirect ~ open redirect), Bölüm 23 (JWT/idtoken doğrulama), Bölüm 25 (clientsecret).

Bu bölümün kazanımı

OAuth 2.0 (yetkilendirme) ile OIDC (kimlik) arasındaki farkı; authorization code akışını ve onu koruyan üç parametreyi (redirecturi, state, PKCE); ve OIDC güvenliğinin neden bir zincir olduğunu — kimlik sağlayıcı (IdP) özneyi doğrulamalı, güvenen taraf (RP) token'ı doğrulamalı — göreceksiniz.

1. Giriş

"Google ile giriş yap", "Apple ile giriş yap", "bir uygulamaya takviminize erişim izni verin" — bunların hepsi OAuth 2.0 ve onun kimlik katmanı OIDC (OpenID Connect) ile çalışır. Bu protokoller modern kimlik ve yetki delegasyonunun bel kemiğidir; ama karmaşıklıkları ve ince ayrıntıları, onları hataya çok açık kılar. Bir OAuth/OIDC hatası genellikle tam hesap devralma ile sonuçlanır — çünkü bu protokoller doğrudan "kimsin ve neye erişebilirsin" sorusunu yanıtlar.

Bu bölüm, Bölüm 23'ün (JWT) üstüne oturur: OIDC'nin kimlik iddiası olan id_token bir JWT'dir ve onun güvenliği JWT doğrulamasına dayanır. Ama OAuth/OIDC, JWT'nin ötesinde kendi akış-seviyesi risklerini ekler: yanlış redirect_uri doğrulaması token'ı saldırgana yönlendirir, eksik state CSRF'e (Bölüm 17) açar, PKCE eksikliği kod ele geçirmeye izin verir.

Bu risklerin ve "geçerli imza yeterli değildir" dersinin en çarpıcı kanıtı, 2020'deki "Sign in with Apple" açığıdır (Bölüm 11): Apple'ın sunucusu herhangi bir e-posta için geçerli imzalı bir id_token üretebiliyordu; bu token'a körü körüne güvenen üçüncü taraf uygulamalarda (Dropbox, Spotify, Airbnb gibi) herhangi bir hesap devralınabiliyordu. Bhavuk Jain bu bulguyla Apple'dan 100.000 dolar ödül aldı. Bu vaka, OIDC güvenliğinin neden hem IdP hem RP tarafında doğru olması gereken bir zincir olduğunu gösterir.


2. Temel Teori

OAuth 2.0 vs OIDC — kritik ayrım. - OAuth 2.0: Bir yetkilendirme (authorization) çerçevesidir. "X uygulamasının Y kaynağıma (takvim, fotoğraf) erişmesine izin ver." Erişimle ilgilenir, kimlikle değil. Ürettiği access_token bir erişim anahtarıdır, kimlik kanıtı değildir. - OIDC (OpenID Connect): OAuth 2.0 üstüne inşa edilen bir kimlik (authentication) katmanıdır. Kimliği iddia eden bir id_token (JWT) ekler. "Bu kullanıcı kim?" sorusunu yanıtlar.

Yaygın ve tehlikeli hata: OAuth access_token'ını kimlik doğrulama için kullanmak. access_token yalnızca "bu taşıyıcının şu kaynağa erişimi var" der; hangi kullanıcı için üretildiğini güvenli biçimde iddia etmez. Kimlik için OIDC id_token'ı (uygun doğrulamayla) kullanılmalıdır.

Roller:

Rol Kim
Resource Owner Kullanıcı (kaynağın sahibi)
Client (RP) Erişim isteyen uygulama (güvenen taraf)
Authorization Server / IdP Token üreten sunucu (Google, Apple)
Resource Server Kaynağı tutan API

Authorization Code akışı (önerilen). Adımlar: 1. Client, kullanıcıyı IdP'ye yönlendirir: client_id, redirect_uri, scope, state, code_challenge (PKCE) ile. 2. Kullanıcı IdP'de kimlik doğrular ve onay verir. 3. IdP, kullanıcıyı redirect_uri'ye bir authorization code + state ile geri yönlendirir. 4. Client, kodu (+ client_secret / PKCE code_verifier) arka kanaldan (back-channel) token endpoint'te token'larla takas eder. 5. Client access_token (+ OIDC ise id_token) alır.

Akışı koruyan üç parametre — her biri bir saldırıyı kapatır:

Parametre Ne yapar Kapattığı saldırı
redirect_uri (tam eşleşme) Kodun/token'ın nereye döneceğini sabitler Kod/token hırsızlığı (saldırgan sitesine yönlendirme)
state Akışı istemci oturumuna bağlar CSRF / login CSRF / hesap bağlama (Bölüm 17)
PKCE (code_challenge/verifier) Kodu, onu isteyen istemciye bağlar Authorization code interception

Terk edilen: implicit flow. Eski "implicit" akış, token'ı doğrudan URL fragment'ında döndürüyordu → token, Referer, tarayıcı geçmişi ve loglara sızıyordu. Modern öneri (OAuth 2.1): tüm istemciler için Authorization Code + PKCE.

OIDC id_token doğrulaması — imza tek başına yetmez. RP, id_token'ı alınca şunları doğrulamalıdır: imza (Bölüm 23), iss (yayınlayan doğru IdP mi), aud (bu token bu client için mi — client_id), exp (süre), ve nonce (tekrar/replay koruması). Sign in with Apple dersi tam burada: geçerli imzalı bir token bile, hangi kullanıcı için ve hangi uygulama için üretildiği doğrulanmazsa güvenilmez.


3. Mimarisel Bakış

 AUTHORIZATION CODE + PKCE (güvenli):
   Client → IdP'ye yönlendir: client_id, redirect_uri, scope,
            state=RASTGELE, code_challenge=hash(verifier)
        ↓  kullanıcı kimlik doğrular + onaylar
   IdP → redirect_uri'ye: code + state
        ↓  Client: gelen state == gönderdiğim state? (CSRF — Böl. 17)
   Client → (arka kanal) token endpoint: code + code_verifier + client_secret
        ↓  IdP: code_challenge == hash(code_verifier)? (PKCE)
   IdP → access_token (+ id_token)
        ↓  RP: id_token doğrula — imza + iss + aud + exp + nonce (Böl. 23)
   → güvenli kimlik/erişim

 REDIRECT_URI SALDIRISI:
   redirect_uri gevşek doğrulanırsa (wildcard/prefix)
   Saldırgan → redirect_uri=https://saldirgan.com ile akış başlatır
        → code/token SALDIRGANA döner → hesap devralma

 SIGN IN WITH APPLE (IdP zinciri kırık):
   IdP, HERHANGİ bir e-posta için geçerli imzalı id_token üretir
        ↓  RP yalnızca "imza geçerli + e-posta X" diye güvenirse
   → saldırgan kurbanın e-postasıyla token alıp hesabı devralır
        ✗ IdP özneyi doğrulamalı + RP aud/iss/nonce doğrulamalı

Kritik gözlem: OAuth/OIDC güvenliği bir zincirdir — IdP doğru token üretmeli (özneyi doğrulamalı), RP token'ı doğru doğrulamalı (imza + iddialar). Zincirin herhangi bir halkası kırılırsa hesap devralma olur.


4. Güvensiz Kod

Gerçekçi bir "sosyal giriş" (OIDC) istemci akışı:

<?php
// ⚠️ GÜVENSİZ — OAuth/OIDC istemci hataları
declare(strict_types=1);
session_start();

// 1) Yönlendirme: state yok (CSRF), PKCE yok
$authUrl = "https://idp.example.com/authorize?client_id=$clientId"
         . "&redirect_uri=" . $_GET['return_to']    // kullanıcı-kontrollü redirect_uri!
         . "&response_type=token";                   // implicit flow (terk edilmiş)
header("Location: $authUrl");

// 2) Callback: state doğrulaması yok, id_token doğrulaması eksik
$idToken = $_GET['id_token'];
$claims = json_decode(base64_decode(explode('.', $idToken)[1]), true);  // imza kontrol YOK
$email = $claims['email'];                            // aud/iss/nonce kontrol YOK

// 3) Kimliği yalnızca e-postaya göre kur (Sign in with Apple hatası)
$user = User::firstOrCreate(['email' => $email]);     // token kime ait, doğrulanmadı
login($user);

// 4) access_token'ı kimlik için kullanmak (kavramsal hata)
// "access_token geçerli → kullanıcı giriş yaptı" — YANLIŞ

5. Açığın Analizi

redirect_uri = $_GET['return_to'] (kullanıcı-kontrollü)Kod/token hırsızlığı. redirect_uri istemciden alınıyor; saldırgan bunu kendi sitesine ayarlayıp akışı başlatır, böylece authorization code/token saldırgana döner. redirect_uri, IdP'de önceden kayıtlı değerlere karşı tam eşleşme ile doğrulanmalıdır (wildcard/prefix değil — Bölüm 20 open redirect mantığı).

response_type=token (implicit flow) — Terk edilmiş akış; token doğrudan URL'de döner ve Referer/geçmiş/loglara sızar. Authorization Code + PKCE kullanılmalı.

state yokCSRF (Bölüm 17). Akış istemci oturumuna bağlanmadığından, saldırgan bir "login CSRF" veya hesap-bağlama saldırısı yapar: kurbanı, saldırganın hesabına bağlı bir akışa sokar; kurban farkında olmadan saldırganın kontrol ettiği bir kimliğe giriş yapar veya kurbanın hesabına saldırganın sosyal kimliği bağlanır.

id_token doğrulaması eksik — Kod, id_token'ın imzasını (Bölüm 23), iss, aud, exp, nonce'unu doğrulamadan payload'ı okuyor. İmza doğrulanmazsa saldırgan token'ı forge eder; aud doğrulanmazsa başka bir uygulama için üretilmiş token bu uygulamada geçer (token substitution); nonce doğrulanmazsa eski token tekrar oynatılır.

Kimliği yalnızca e-postaya göre kurmak — Sign in with Apple hatasının ta kendisi. Token'ın gerçekten o kullanıcı için ve bu uygulama için üretildiği doğrulanmadan, yalnızca email iddiasına güvenmek hesap devralmaya açıktır.

access_token'ı kimlik için kullanmak — Kavramsal hata: access_token erişim verir, kimlik iddia etmez. Kimlik için doğrulanmış id_token gerekir.

Kök sorun: akış parametreleri (redirect_uri/state/PKCE) korunmuyor ve id_token gereğince doğrulanmıyor. OAuth/OIDC zincirinin RP tarafı kırık.


6. Hacker Bakış Açısı

Saldırgan OAuth/OIDC'yi nasıl hedefler?

redirect_uri'yi yoklar. İlk denediği, redirect_uri'yi kendi kontrol ettiği bir değere değiştirmektir: tam eşleşme yoksa (wildcard, prefix, alt-yol, açık yönlendirme zinciri), authorization code/token saldırgana döner → hesap devralma. Bu, OAuth'un en klasik saldırısıdır.

state'i test eder. state yoksa veya doğrulanmıyorsa, CSRF/login CSRF kurar: kurbanı saldırganın başlattığı bir akışa sokup hesap-bağlama veya oturum sabitleme yapar.

PKCE eksikliğini arar. Özellikle mobil/SPA istemcilerde, authorization code'u ele geçirebiliyorsa (loglar, referer, kötü uygulama), PKCE yoksa kodu token'a takas eder. PKCE varsa code_verifier olmadan takas başarısız olur.

id_token doğrulamasını test eder. İmza doğrulanmıyor mu (Bölüm 23 saldırıları)? aud doğrulanmıyor mu (başka uygulamanın token'ını buraya sunma — token substitution)? iss doğrulanmıyor mu (sahte IdP)? nonce yok mu (replay)? Bu boşluklardan biri hesap devralmaya yeter.

IdP'yi ve iddiaları sorgular. Sign in with Apple'da olduğu gibi, IdP'nin özneyi doğrulayıp doğrulamadığını test eder; token'ı yalnızca email iddiasına dayanarak kabul eden RP'leri arar.

Token sızıntısı arar. Referer başlıkları, tarayıcı geçmişi, loglar, açık yönlendirmeler — token/kod'un sızabileceği her kanal.

Savunmacı dersi: Saldırgan zinciri en zayıf halkasından — çoğu zaman gevşek redirect_uri veya eksik id_token doğrulaması — kırar. Savunma her halkayı (redirect_uri, state, PKCE, token doğrulama) ayrı ayrı sağlamlaştırmalıdır.


7. Exploit Mantığı

Bu bölüm çalıştırılabilir saldırı içermez. OAuth/OIDC hatalarının neden bu kadar yıkıcı olduğu kavramsaldır:

  • Doğrudan hesap devralma. Bu protokoller kimliği ve erişimi belirlediğinden, bir hata neredeyse her zaman doğrudan hesap devralmayla sonuçlanır — parola kırmaya, kimlik hırsızlığına gerek kalmadan.
  • Ölçek. Sign in with Apple gibi bir IdP hatası, o IdP'yi kullanan tüm uygulamaları etkiler (Dropbox, Spotify, Airbnb...). Coalfire'ın deyimiyle "neredeyse tüm diğer güvenliği anlamsız kıldı".
  • Zincir doğası. Güvenlik hem IdP (özneyi doğrula) hem RP (token'ı doğrula) tarafında doğru olmalıdır; bir taraf hata yaparsa diğerinin doğru olması bazen yetmez. Sign in with Apple'da IdP hata yaptı, ek önlem almayan RP'ler savunmasız kaldı.
  • "Geçerli imza" tuzağı. İmzanın geçerli olması gerekli ama yeterli değildir (Bölüm 23). Token'ın kim için ve hangi uygulama için üretildiği (aud, özne doğrulaması) da doğrulanmalıdır.

Araştırmacının çerçevesi: (a) redirect_uri tam eşleşme mi, (b) state var mı, (c) PKCE var mı, (d) id_token tam doğrulanıyor mu (imza+iss+aud+nonce+exp), (e) IdP özneyi doğruluyor mu. Savunma bu halkaların hepsini kapatır.


8. Güvenli Kod

Authorization Code + PKCE + state + tam id_token doğrulaması:

<?php
// ✅ GÜVENLİ — Authorization Code + PKCE + state + id_token doğrulama
declare(strict_types=1);
session_start();

use Firebase\JWT\JWT;
use Firebase\JWT\Key;

// --- 1) Yönlendirme: state + PKCE üret ---
$state = bin2hex(random_bytes(16));                 // CSRF (Böl. 17)
$verifier = bin2hex(random_bytes(32));              // PKCE
$challenge = rtrim(strtr(base64_encode(hash('sha256', $verifier, true)), '+/', '-_'), '=');

$_SESSION['oauth_state'] = $state;                  // oturuma bağla
$_SESSION['pkce_verifier'] = $verifier;
$nonce = bin2hex(random_bytes(16));
$_SESSION['oidc_nonce'] = $nonce;

$authUrl = 'https://idp.example.com/authorize?' . http_build_query([
    'client_id'             => $clientId,
    'redirect_uri'          => 'https://app.example.com/callback',  // SABİT, önceden kayıtlı
    'response_type'         => 'code',              // authorization code (implicit değil)
    'scope'                 => 'openid email profile',  // minimal scope
    'state'                 => $state,
    'nonce'                 => $nonce,
    'code_challenge'        => $challenge,
    'code_challenge_method' => 'S256',
]);
header("Location: $authUrl");
exit;

// --- 2) Callback: state doğrula, kodu arka kanaldan takas et ---
if (!hash_equals($_SESSION['oauth_state'] ?? '', $_GET['state'] ?? '')) {
    http_response_code(400); exit('Geçersiz state (CSRF?)');
}
$code = $_GET['code'] ?? '';

// Arka kanal token takası (client_secret + PKCE verifier)
$resp = httpPost('https://idp.example.com/token', [
    'grant_type'    => 'authorization_code',
    'code'          => $code,
    'redirect_uri'  => 'https://app.example.com/callback',
    'client_id'     => $clientId,
    'client_secret' => getenv('OAUTH_CLIENT_SECRET'),   // sır yöneticisi (Böl. 25)
    'code_verifier' => $_SESSION['pkce_verifier'],
]);
$tokens = json_decode($resp, true);

// --- 3) id_token'ı TAM doğrula (Böl. 23) ---
$idToken = $tokens['id_token'];
$jwks = getIdpPublicKey();                          // IdP'nin JWKS'inden açık anahtar
$decoded = JWT::decode($idToken, $jwks);            // imza (algoritma sabit, Böl. 23)

if (($decoded->iss ?? '') !== 'https://idp.example.com'   // yayınlayan
    || ($decoded->aud ?? '') !== $clientId                // BU uygulama için mi (aud)
    || ($decoded->nonce ?? '') !== ($_SESSION['oidc_nonce'] ?? '')) {  // replay
    http_response_code(401); exit('id_token doğrulaması başarısız');
}

// --- 4) Kimliği STABİL özne (sub) üzerinden kur, salt e-posta değil ---
$user = User::firstOrCreate(
    ['idp_sub' => $decoded->sub],                   // IdP'nin kararlı kullanıcı kimliği
    ['email' => $decoded->email ?? null]
);
login($user);
unset($_SESSION['oauth_state'], $_SESSION['pkce_verifier'], $_SESSION['oidc_nonce']);

Öne çıkan modern kalıplar: - Authorization Code + PKCE (tüm istemciler): Implicit flow'u terk et; kodu arka kanaldan takas et. PKCE, kod ele geçirmeyi kapatır (mobil/SPA dahil). - redirect_uri tam eşleşme: IdP'de önceden kayıtlı, sabit URI; kullanıcıdan asla alınmaz (Bölüm 20). - state (Bölüm 17): random_bytes, oturuma bağlı, hash_equals ile doğrulanır; CSRF/login CSRF'i kapatır. - id_token tam doğrulaması (Bölüm 23): İmza + iss + aud (= client_id) + exp + nonce. "Geçerli imza yeterli değildir." - Kararlı özne (sub): Kimliği IdP'nin kararlı sub'ına bağla; salt email'e güvenme (Sign in with Apple dersi). - Minimal scope: Yalnızca gerekli izinler. - client_secret sır yöneticisinde (Bölüm 25): Kodda değil. - access_token'ı kimlik için kullanma: Kimlik = doğrulanmış id_token.


9. Patch Analizi

Neden işe yarar? Her savunma bir zincir halkasını sağlamlaştırır: tam-eşleşme redirect_uri kod/token hırsızlığını, state CSRF'i (Bölüm 17), PKCE kod ele geçirmeyi, tam id_token doğrulaması (imza + iss + aud + nonce) forge/substitution/replay'i kapatır. Kimliği kararlı sub'a bağlamak, Sign in with Apple türü "salt e-postaya güven" hatasını önler. Bunlar birlikte, OAuth/OIDC zincirinin RP tarafını bütünüyle korur.

Saldırı-savunma haritası:

Saldırı Onu kapatan
Kod/token hırsızlığı redirect_uri tam eşleşme
CSRF / login CSRF state (Bölüm 17)
Kod ele geçirme PKCE
Token forge id_token imza doğrulama (Bölüm 23)
Token substitution aud doğrulama
Replay nonce doğrulama
Sahte IdP iss doğrulama
Token sızıntısı Authorization Code (implicit değil) + arka kanal
Salt-email ATO Kararlı sub'a bağlama

IdP tarafı (Sign in with Apple dersi): RP savunması güçlü olsa da, IdP özneyi doğrulamazsa (herhangi bir e-posta için token üretirse) zincir yine kırılır. Bu yüzden güvenilir IdP seçimi ve — mümkünse — RP tarafında ek doğrulama (örn. e-posta doğrulama, sub kullanımı) önemlidir.

Performans: Ek parametreler ve doğrulamalar birkaç hash/karşılaştırmadır; ihmal edilebilir. Arka kanal takası bir ek HTTP isteğidir ama güvenlik için gereklidir.


10. Gerçek Hayat Senaryosu

Kurgu — bir SaaS "Google/Apple ile giriş" entegrasyonu. Uygulama, sosyal girişi hızlıca eklemek için id_token'ı yalnızca imzasını ve email iddiasını kontrol ederek kabul ediyor; aud, iss, nonce doğrulanmıyor ve redirect_uri gevşek. İki ayrı saldırı mümkün: (1) saldırgan, başka bir uygulama için üretilmiş geçerli bir id_token'ı buraya sunar (aud doğrulanmadığından geçer — token substitution); (2) redirect_uri gevşek olduğundan authorization code saldırgana yönlendirilir. Her ikisi de hesap devralmaya çıkar. Dersler: (1) id_token doğrulaması imza + iss + aud + nonce içermeli; (2) redirect_uri tam eşleşmeli; (3) kimlik kararlı sub'a bağlanmalı — "geçerli imza + e-posta" yeterli değildir.


11. Gerçek CVE Analizi — "Sign in with Apple" Hesap Devralma (2020)

Bhavuk Jain'in açıklaması, BleepingComputer, Threatpost ve BankInfoSecurity ile doğrulanmıştır. OIDC güvenliğinin bir zincir olduğunu kanıtlayan vakadır.

Özet. Nisan 2020'de güvenlik araştırmacısı Bhavuk Jain, "Sign in with Apple" özelliğinde herhangi bir üçüncü taraf hesabının tam devralınmasına yol açabilecek kritik bir sıfır-gün buldu ve Apple'dan 100.000 dolar ödül aldı. Sign in with Apple, OAuth 2.0'a benzer biçimde çalışır: kullanıcı ya bir JWT (id_token) ya da JWT üretmek için bir kodla kimlik doğrular. Apple, kullanıcıya gerçek e-postasını paylaşma veya Apple'ın ürettiği bir "relay" (aktarma) e-postası kullanma seçeneği sunar; onaydan sonra bu e-postayı içeren bir JWT üretir ve üçüncü taraf uygulama bu JWT ile kullanıcıyı tanır/giriş yaptırır.

Teknik neden — IdP özneyi doğrulamadı. Jain'in bulduğu kusur şuydu: Apple'ın sunucusundan herhangi bir e-posta kimliği için JWT talep edilebiliyordu ve bu token'ların imzası Apple'ın açık anahtarıyla doğrulandığında geçerli görünüyordu. Yani IdP (Apple), token'ı isteyen kişinin gerçekten o e-postanın/Apple ID'nin sahibi olup olmadığını doğrulamadan, o e-posta için geçerli imzalı bir id_token üretiyordu. Sonuç: bir saldırgan, kurbanın e-postasını içeren geçerli imzalı bir JWT elde edip, bu token'a güvenen üçüncü taraf uygulamalarda kurbanın hesabını devralabiliyordu — kurbanın geçerli bir Apple ID'si olsun ya da olmasın. Kullanıcı e-postasını gizlemeyi seçse (relay e-posta) bile saldırı çalışıyordu.

Bu, Bölüm 23'ün "geçerli imza ≠ güvenilir iddia" dersinin en net kanıtıdır: token'ın imzası gerçekten geçerliydi (Apple imzalamıştı), ama içindeki özne iddiası güvenilmezdi çünkü IdP özneyi doğrulamamıştı. Ayrıca RP tarafı için ders şudur: yalnızca "imza geçerli + e-posta X" diye güvenmek yetmez; aud/sub/nonce doğrulaması ve mümkünse ek önlemler gerekir. Nitekim Jain, açığın "kendi ek güvenlik önlemlerini uygulamayan" üçüncü taraf uygulamaları etkilediğini vurguladı.

Etki. Sign in with Apple, diğer sosyal girişleri destekleyen uygulamalar için zorunlu olduğundan, açık Dropbox, Spotify, Airbnb, Giphy gibi çok geniş bir uygulama tabanını potansiyel olarak etkiliyordu — "çok az çabayla tam hesap devralma", kolayca otomatikleştirilebilir. Apple açığı yamaladı ve log incelemesiyle kötüye kullanım olmadığını belirledi.

Çıkarılacak dersler: 1. OIDC güvenliği bir zincirdir. IdP özneyi doğrulamalı; RP token'ı (imza + iss + aud + nonce) doğrulamalı. Bir halka kırılırsa hesap devralma olur. 2. Geçerli imza yeterli değildir (Bölüm 23). Token'ın kim için ve hangi uygulama için üretildiği de doğrulanmalıdır. 3. Kimliği kararlı özneye bağla. Salt email iddiasına güvenmek kırılgandır; sub ve ek doğrulama kullanılmalı. 4. RP kendi savunmasını eklemeli. IdP'ye tam güven riskli; ek doğrulama katmanları (Bölüm 1, derinlemesine savunma) hasarı sınırlar.


12. Detection

Kod incelemede: Akış parametrelerini ve id_token doğrulamasını arayın:

grep -rnE 'redirect_uri|return_to|callback' src/ | grep -iE '_GET|_POST|_REQUEST'  # kullanıcı-kontrollü redirect
grep -rn  'state'  src/ | grep -i oauth        # state üretiliyor/doğrulanıyor mu?
grep -rn  'code_challenge\|code_verifier\|pkce' src/   # PKCE var mı?
grep -rnE 'response_type=token|implicit' src/  # implicit flow (terk edilmeli)
grep -rn  'id_token' src/ | grep -viE 'aud|iss|nonce|verify|decode'  # eksik doğrulama

Kontroller: redirect_uri tam eşleşme mi? state var/doğrulanıyor mu? PKCE var mı? id_token imza+iss+aud+nonce doğrulanıyor mu? Kimlik sub'a mı bağlı?

SAST: Kullanıcı-kontrollü redirect_uri, eksik state/PKCE, eksik id_token doğrulaması için kurallar; OAuth/OIDC-farkında araçlar tercih edilir.

DAST/manuel: redirect_uri manipülasyonu, state olmadan CSRF, PKCE atlama, farklı aud'lu token substitution testleri.

Loglar/SIEM: Beklenmeyen redirect_uri değerleri; state uyuşmazlığı olan callback'ler; farklı aud/iss ile gelen token'lar; aynı sub/e-posta için olağandışı hesap erişimi. OAuth callback anomalileri hesap devralma tespitinde değerlidir.


13. Prevention

  • Authorization Code + PKCE (tüm istemciler): Implicit flow'u terk et; arka kanal takası.
  • redirect_uri tam eşleşme: Önceden kayıtlı, sabit; kullanıcıdan alma (Bölüm 20).
  • state (Bölüm 17): random_bytes, oturuma bağlı, hash_equals ile doğrula.
  • id_token tam doğrula (Bölüm 23): İmza + iss + aud (=client_id) + exp + nonce.
  • Kimliği kararlı sub'a bağla: Salt e-postaya güvenme (Sign in with Apple dersi).
  • access_token'ı kimlik için kullanma: Kimlik = id_token.
  • Minimal scope + token'ı sızdırma: Yalnızca gerekli izinler; Referer/log/URL sızıntısını önle.
  • client_secret sır yöneticisinde (Bölüm 25).
  • Güvenilir IdP + RP ek doğrulaması: Derinlemesine savunma (Bölüm 1).

14. Mitigation

  • Acil: redirect_uri'yi tam eşleşmeye çevir; state + PKCE ekle; id_token tam doğrulaması (aud/iss/nonce) ekle; implicit flow'u kapat.
  • Geçici: Zayıf doğrulama nedeniyle devralınmış olabilecek hesapları belirle; şüpheli oturumları iptal et; sosyal-kimlik bağlarını yeniden doğrula; client_secret sızmışsa döndür.
  • Kalıcı: Güvenli akış kalıbını (code+PKCE+state+tam doğrulama) standartlaştır; kimliği sub'a bağla; OAuth/OIDC testlerini CI'a ekle; güvenilir IdP + RP ek doğrulama.

15. Checklist

  • [ ] Authorization Code + PKCE kullanılıyor mu (implicit flow yok)?
  • [ ] redirect_uri önceden kayıtlı ve tam eşleşme mi (kullanıcı-kontrollü değil)?
  • [ ] state üretiliyor, oturuma bağlanıyor ve hash_equals ile doğrulanıyor mu (CSRF)?
  • [ ] id_token imza + iss + aud (=client_id) + exp + nonce ile tam doğrulanıyor mu?
  • [ ] Kimlik kararlı sub'a mı bağlı (salt e-posta değil)?
  • [ ] access_token kimlik doğrulama için kullanılmıyor mu?
  • [ ] Scope minimal mi; token Referer/log/URL'e sızmıyor mu?
  • [ ] client_secret sır yöneticisinde mi (Bölüm 25)?
  • [ ] JWT kütüphanesi güvenli kullanılıyor mu (algoritma sabit — Bölüm 23)?

16. Laboratuvar

Lab 24.1 — redirect_uri manipülasyonu. İzole ortamda kullanıcı-kontrollü redirect_uri kabul eden bir istemci kur; kodu farklı bir hedefe yönlendirmeyi göster. Tam-eşleşme doğrulamasıyla kapat.

Lab 24.2 — state (CSRF). state üretmeyen bir akış yaz; login CSRF/hesap-bağlama senaryosunu modelle. state üretip hash_equals ile doğrulayarak düzelt (Bölüm 17'ye bağla).

Lab 24.3 — PKCE. PKCE'siz bir akışta ele geçirilen bir kodu takas et; PKCE ekleyip code_verifier olmadan takasın başarısız olduğunu gözlemle.

Lab 24.4 — id_token doğrulama. Yalnızca imzayı kontrol eden bir doğrulayıcıya farklı aud'lu (başka uygulama için üretilmiş) geçerli bir token sun; kabul edildiğini gör. aud/iss/nonce doğrulaması ekleyip düzelt (Sign in with Apple dersi).


17. Quiz

  1. OAuth 2.0 ile OIDC arasındaki temel fark nedir (yetkilendirme vs kimlik)?
  2. access_token'ı kimlik doğrulama için kullanmak neden yanlıştır?
  3. Authorization Code akışının adımlarını özetleyin. Arka kanal takası neden önemlidir?
  4. redirect_uri neden tam eşleşme ile doğrulanmalıdır? Gevşek doğrulama neye yol açar?
  5. state parametresi hangi saldırıyı kapatır (Bölüm 17'ye atıfla)?
  6. PKCE nedir ve hangi saldırıyı önler? Neden artık tüm istemciler için önerilir?
  7. Implicit flow neden terk edildi?
  8. id_token doğrulamasında hangi beş şey kontrol edilmeli ve her biri neyi önler?
  9. "Geçerli imza yeterli değildir" ne demektir (Bölüm 23'e atıfla)?
  10. Sign in with Apple açığında IdP hangi hatayı yaptı? Bu neden bir "zincir" sorunudur?
  11. Kimliği neden salt email yerine kararlı sub'a bağlamalıyız?
  12. Token substitution (aud atlatma) nasıl çalışır ve nasıl önlenir?

18. Kaynakça

  • IETF RFC 6749 (OAuth 2.0), RFC 7636 (PKCE), RFC 6819 ve OAuth 2.0 Security Best Current Practice (RFC 9700); OpenID Connect Core spesifikasyonu.
  • OWASP, OAuth 2.0 Cheat Sheet; Testing for OAuth Weaknesses (WSTG).
  • MITRE, CWE-601 (Open Redirect — redirect_uri), CWE-352 (CSRF — state), CWE-347 (imza doğrulama — id_token).
  • Bhavuk Jain, Zero-day in Sign in with Apple (2020); BleepingComputer, Threatpost, BankInfoSecurity haberleri.
  • PortSwigger Web Security Academy, OAuth 2.0 authentication vulnerabilities.
  • OAuth 2.1 taslağı (Authorization Code + PKCE varsayılanı, implicit flow'un kaldırılması).