Bölüm 15
Insecure Direct Object Reference (IDOR)
Bölüm 14 (yetkilendirme, deny-by-default, complete mediation). Bu bölüm, Bölüm 14'ün dikey yükseltmesini yatay/nesne-düzeyi erişimle tamamlar.
IDOR'u, "bir kullanıcının başka bir kullanıcının nesnesine, yalnızca kimliğini değiştirerek erişmesi" olarak kavrayacak; en kritik dersi — rastgele/UUID kimlikler IDOR'u çözmez, nesne-düzeyi yetkilendirme çözer — içselleştireceksiniz. Bu, OWASP API Güvenliği listesinin 1 numaralı riskidir (BOLA).
1. Giriş
IDOR, kavramsal olarak en basit ama pratikte en yaygın açıklardan biridir. Öz olarak: bir uygulama, kullanıcının sağladığı bir tanımlayıcıyı (bir sayı, bir ID) doğrudan bir arka uç nesnesine (bir kayıt, bir dosya) eşler ve o nesneye erişmeden önce "bu kullanıcının buna hakkı var mı?" sorusunu sormaz. Sonuç: kullanıcı, URL'deki veya istekteki kimliği değiştirerek başka birinin verisine erişir.
Basitliğine rağmen IDOR, tarihin en büyük veri sızıntılarından bazılarının kökenindedir. 2019'da First American Financial'ın 885 milyon belgelik sızıntısı (Bölüm 11) tek bir IDOR'du: belge URL'lerindeki sıralı numarayı bir artırıp azaltmak, başka müşterilerin banka hesaplarını, sosyal güvenlik numaralarını ve ipotek belgelerini açığa çıkarıyordu — hiçbir kimlik doğrulama gerekmeden. API çağının gelmesiyle IDOR daha da kritikleşti; OWASP API Güvenliği Top 10 listesinde 1 numarada yer alır ve orada BOLA (Broken Object Level Authorization — Bozuk Nesne Düzeyi Yetkilendirme) olarak adlandırılır.
Bu bölümün merkezî mesajı, çok yaygın bir yanılgıyı düzeltir: IDOR'un çözümü kimlikleri tahmin edilemez yapmak (UUID) değildir. Tahmin edilemezlik yalnızca belirsizlik (obscurity) sağlar; sızan veya paylaşılan bir UUID hâlâ erişim verir. Gerçek çözüm, her nesne erişiminde sahipliği/yetkiyi kontrol etmektir.
2. Temel Teori
"Direct object reference" nedir? Uygulamalar iç nesneleri tanımlayıcılarla adresler: user_id=42, order=1001, file=doc_555. Bu tanımlayıcı istemciye ifşa edilip (URL, form, API yolu) sonra istemciden geri alındığında, "doğrudan nesne referansı" olur. Bu, tek başına kötü değildir — Google Docs, Dropbox gibi servisler de paylaşılabilir bağlantılarda böyle referanslar kullanır. Sorun, referansın yetki kontrolü olmadan kullanılmasıdır. "Insecure" (güvensiz) kelimesi tam olarak bu eksik kontrolü işaret eder.
IDOR = yatay erişim kontrolü kusuru. Bölüm 14'teki ayrımı hatırlayın: - Dikey yükseltme: düşük yetki → yüksek yetki (fonksiyon düzeyi). Bölüm 14. - Yatay erişim: kullanıcı A → kullanıcı B'nin nesnesi (nesne düzeyi). IDOR budur.
IDOR'da saldırgan yeni bir yetki kazanmaz; kendi yetki düzeyinde kalır ama başka birinin verisine ulaşır. Örneğin sıradan bir kullanıcı, /invoice/1001 yerine /invoice/1002 isteyerek başka bir müşterinin faturasını görür.
Referansların geldiği yerler. IDOR yalnızca URL'de değildir; nesne kimliği taşıyan her yer risktir: URL yolu (/api/users/42), sorgu dizesi (?id=42), POST gövdesi, gizli form alanları, çerezler, JSON alanları, hatta dosya adları. Saldırgan bunların hepsini dener.
İki kök çözüm:
1. Sorguyu kullanıcıya daralt (scope to user). Nesneyi getirirken sorguya sahiplik koşulunu ekle: WHERE id = ? AND owner_id = :currentUser. Böylece başka birinin nesnesi hiç dönmez.
2. Getirilen nesne üzerinde yetki ver. Önce nesneyi getir, sonra sahiplik/yetki kontrolü yap (Bölüm 14'ün "gerçek nesne üzerinde karar" kalıbının nesne düzeyi hâli).
Neden UUID çözüm değildir? Sıralı kimlikler numaralandırmayı kolaylaştırır (First American: +1 ile bir sonraki kayıt). UUID/rastgele kimlik, kaba numaralandırmayı zorlaştırır — ama bu yalnızca belirsizliktir. UUID bir yerde sızarsa (loglar, Referer başlığı, paylaşılan bağlantı, tarayıcı geçmişi, hata mesajı), erişim yine açılır; çünkü asıl eksik olan yetki kontrolüdür. UUID, derinlemesine savunmanın (Bölüm 1) bir katmanı olabilir, ama tek savunma olamaz.
3. Mimarisel Bakış
GÜVENSİZ (referans → nesne, yetki kontrolü YOK):
Kullanıcı A (kimliği: 42) → GET /api/invoices/1002
↓ ╳ güven sınırı
SELECT * FROM invoices WHERE id = 1002 ← sahiplik SORULMADI
↓
Fatura 1002 (kullanıcı B'nin) → A'ya döner → IDOR
GÜVENLİ — Yöntem 1 (scope to user):
GET /api/invoices/1002 (kullanıcı A, id=42)
↓
SELECT * FROM invoices WHERE id = 1002 AND owner_id = 42
↓
Eşleşme yok → 404/403 → B'nin verisi ASLA dönmez
GÜVENLİ — Yöntem 2 (nesne üzerinde yetki):
$invoice = Invoice::find(1002)
↓
authorize('view', $invoice) ← $invoice->owner_id === currentUser?
↓
Değilse 403; ise döndür
UUID YANILGISI:
/api/invoices/9f2a-...-c31 ← tahmin zor AMA
↓ UUID loglara/Referer'a/paylaşıma sızarsa
Yetki kontrolü yoksa → erişim yine açılır (belirsizlik ≠ güvenlik)
Kritik gözlem: güvenli tasarımda erişim kararı daima kimliğe (kim istiyor) ve nesneye (kimin) bağlıdır — kimliğin tahmin edilebilirliğine değil.
4. Güvensiz Kod
Gerçekçi bir "fatura / profil / dosya" erişim kümesi:
<?php
// ⚠️ GÜVENSİZ — nesne düzeyi yetki kontrolü yok (IDOR)
declare(strict_types=1);
// 1) Fatura görüntüleme — sahiplik sorulmuyor
$id = (int)$_GET['id'];
$invoice = $pdo->query("SELECT * FROM invoices WHERE id = $id")->fetch();
echo json_encode($invoice); // herhangi biri herhangi faturaya erişir
// 2) Profil güncelleme — hedef kullanıcı istemciden
$pdo->prepare('UPDATE profiles SET bio = ? WHERE user_id = ?')
->execute([$_POST['bio'], (int)$_POST['user_id']]); // başkasının profili
// 3) Dosya indirme — kullanıcı yolu doğrudan kontrol ediyor
$file = $_GET['file']; // "invoices/1002.pdf"
readfile('/var/app/private/' . $file); // sahiplik yok (+ path traversal, Böl. 20)
// 4) "UUID kullanıyoruz, güvendeyiz" yanılgısı
$doc = $pdo->prepare('SELECT * FROM documents WHERE uuid = ?');
$doc->execute([$_GET['uuid']]); // yetki yok; UUID sızarsa erişim açık
5. Açığın Analizi
WHERE id = $id (fatura) — Klasik IDOR. Sorgu yalnızca id'ye bakıyor, sahipliğe bakmıyor. Kullanıcı id'yi değiştirerek herhangi bir faturaya erişir. (Ayrıca SQL Injection var — Bölüm 6; iki açık bağımsız.) First American'ın 885 milyonluk sızıntısı tam bu kalıptı, sıralı id ile.
UPDATE profiles ... WHERE user_id = $_POST['user_id'] — Hedef kullanıcının kimliği istemciden geliyor. Saldırgan user_id'yi başkasının yaparak onun profilini değiştirir. Doğrusu: hedef, oturumdaki kimlikten ($_SESSION['uid']) alınmalı, istekten değil.
readfile('.../' . $_GET['file']) — Dosya sahipliği kontrol edilmiyor; kullanıcı yol/dosya adını kontrol ediyor. Başka birinin dosyasına (ve path traversal ile sistem dosyalarına, Bölüm 20) erişilir.
WHERE uuid = $_GET['uuid'] — UUID yanılgısı. Geliştirici "UUID tahmin edilemez, güvendeyim" varsaymış. Ama hiçbir yetki kontrolü yok; UUID bir şekilde sızarsa (paylaşım, log, Referer) erişim açılır. UUID belirsizlik sağlar, güvenlik değil.
Kök sorun: Dördünde de nesne, kim istediğine ve nesnenin kime ait olduğuna bakılmadan döndürülüyor. Referansın tahmin edilebilirliği yalnızca kolaylık farkı yaratır; asıl eksik olan yetki kontrolüdür.
6. Hacker Bakış Açısı
Saldırgan IDOR'u nasıl keşfeder?
Kendi kimliğini gözlemler. Meşru bir hesapla giriş yapıp kendi kaynaklarına erişir ve isteklerdeki nesne kimliklerini not eder: ?id=1001, /api/users/42, user_id=42 gibi. Bunlar "değiştirilecek" adaylardır.
Kimliği değiştirir (fuzzing). Kendi kimliğini komşu değerlerle değiştirir: +1, -1, başka bir hesaptan bildiği kimlikler. Başka birinin verisi dönüyorsa IDOR doğrulanmıştır. Sıralı kimliklerde bu, tüm veri kümesini numaralandırmaya (enumeration) dönüşür — First American'da 885 milyon kayıt.
Her taşıyıcıyı dener. Kimliği yalnızca URL'de değil; POST gövdesinde, gizli alanlarda, çerezlerde, JSON'da, başlıklarda arar. Bir yerde kontrol varken başka yerde olmayabilir.
HTTP fiilini ve uç noktayı değiştirir. GET /api/users/42 korunuyorsa PUT/DELETE denenmemiş olabilir; ya da /api/v1/ korunurken /api/v2/ korunmamış olabilir. Saldırgan bu tutarsızlıkları yoklar.
UUID'yi hafife almaz. Rastgele kimlik görse de, onun sızabileceği kanalları düşünür: paylaşılan bağlantılar, Referer başlığı (dış kaynaklara giden), istemci logları, hata mesajları, eski tarayıcı geçmişi. UUID'yi ele geçirdiğinde yetki kontrolü yoksa erişim açıktır.
Savunmacı dersi: Saldırgan "erişebildiğim ama benim olmayan" her nesneyi sistematik dener. Tek savunma, her nesne erişiminde sahiplik/yetki kontrolüdür — kimliğin ne kadar "gizli" olduğundan bağımsız.
7. Exploit Mantığı
Bu bölüm çalıştırılabilir saldırı içermez. IDOR'un neden bu kadar etkili olduğu kavramsaldır:
- Ölçek. Sıralı kimliklerde tek bir IDOR, tüm veri kümesinin numaralandırılmasına açılır. First American'da bu, 885 milyon kaydın otomatik toplanabilmesi demekti. Etki bir kullanıcıyla sınırlı kalmaz.
- Sessizlik ve iz bırakmama. IDOR isteği meşru bir istekle aynı görünür (geçerli oturum, geçerli uç nokta, sadece farklı kimlik). Başarısız giriş veya hata üretmediğinden klasik alarmları tetiklemez; First American vakasında "acemi bir saldırgan bile fark edilmeden yapabilirdi" denmişti.
- Kimlik doğrulama bile gerekmeyebilir. First American'da uç nokta hiç kimlik doğrulama istemiyordu; IDOR + eksik authN birleşince, saldırganın hesap açması bile gerekmedi.
- Yazma IDOR'u daha yıkıcıdır. Okuma IDOR'u veri sızdırır; yazma/silme IDOR'u (başkasının profilini/siparişini değiştirme) bütünlüğü bozar ve iş mantığı saldırılarına (Bölüm 18) zemin olur.
Araştırmacının çerçevesi: (a) nesne referansı istemci-kontrollü mü, (b) erişimde sahiplik/yetki kontrolü var mı, (c) kimlik sıralı mı (numaralandırma ölçeği). Savunma (b)'yi her zaman uygulayarak, (a) ve (c) ne olursa olsun IDOR'u kapatır.
8. Güvenli Kod
İki tamamlayıcı yöntem — sorguyu daralt ve/veya nesne üzerinde yetki ver:
<?php
// ✅ GÜVENLİ — nesne düzeyi yetkilendirme
declare(strict_types=1);
$currentUserId = (int)$_SESSION['uid']; // kimlik OTURUMDAN, istekten değil
// Yöntem 1: sorguyu kullanıcıya daralt (scope to user)
$stmt = $pdo->prepare('SELECT * FROM invoices WHERE id = ? AND owner_id = ?');
$stmt->execute([(int)$_GET['id'], $currentUserId]);
$invoice = $stmt->fetch();
if (!$invoice) {
http_response_code(404); // "yok" ile "yasak" arasında ayrım sızdırma
exit('Bulunamadı');
}
echo json_encode($invoice);
// Yöntem 2: önce getir, sonra nesne üzerinde yetki ver (Böl. 14 kalıbı)
$profile = Profile::findOrFail((int)$_POST['profile_id']);
if ($profile->user_id !== $currentUserId && !currentUserIsAdmin()) {
http_response_code(403);
exit('İzin yok');
}
$profile->bio = $_POST['bio'];
$profile->save();
// Hedef kullanıcı ASLA istemciden gelmez — oturumdan
$pdo->prepare('UPDATE profiles SET bio = ? WHERE user_id = ?')
->execute([$_POST['bio'], $currentUserId]);
// Dosya erişimi: sahiplik DB'de doğrulanır, dosya adı doğrudan kullanılmaz
$doc = $pdo->prepare('SELECT path FROM documents WHERE id = ? AND owner_id = ?');
$doc->execute([(int)$_GET['doc_id'], $currentUserId]);
$row = $doc->fetch();
if ($row) {
readfile('/var/app/private/' . basename($row['path'])); // + Böl. 20
}
Framework araçları:
// Laravel — Policy nesne düzeyinde çalışır
$invoice = Invoice::findOrFail($id);
$this->authorize('view', $invoice); // InvoicePolicy@view: owner mı?
// route model binding + policy: otomatik nesne + yetki
// Symfony — Voter nesne üzerinde:
$this->denyAccessUnlessGranted('VIEW', $invoice);
Öne çıkan modern kalıplar:
- Scope to user: Sorguya AND owner_id = :current ekle; başkasının nesnesi hiç dönmesin. Genelde en basit ve sağlam yöntem.
- Nesne üzerinde yetki: Getir → sahiplik/yetki kontrol et → işle (Bölüm 14).
- Kimlik oturumdan: Hedef kullanıcı/sahip asla istekten alınmaz; $_SESSION'dan.
- Framework policy/voter: Laravel Policy, Symfony Voter; nesne düzeyi yetkiyi merkezîleştirir ve test edilebilir kılar.
- UUID = ek katman: Rastgele kimlikler numaralandırmayı zorlaştırır (derinlemesine savunma), ama yetki kontrolünün yerine geçmez.
- 404 vs 403: Varlık sızıntısını önlemek için, yetkisiz erişimde bazen "yok" (404) dönmek "yasak" (403) dönmekten daha ihtiyatlıdır.
9. Patch Analizi
Neden işe yarar? Sorguyu kullanıcıya daraltmak, yetkisiz nesnenin veritabanından hiç dönmemesini sağlar — kontrol, veri katmanına gömülür. Nesne üzerinde yetki vermek ise Bölüm 14'ün complete mediation ilkesini nesne düzeyine taşır: her erişim, o nesne için ayrı denetlenir. Her iki yöntem de erişimi "kim + hangi nesne" temelinde karara bağlar; kimliğin tahmin edilebilirliğinden bağımsızdır. Bu, IDOR'u tanım gereği kapatır.
Alternatiflerin karşılaştırması:
| Yaklaşım | IDOR'u çözer mi? | Not |
|---|---|---|
| Sıralı kimlik + yetki yok | ✗ | Kritik; kolay numaralandırma |
| UUID + yetki yok | ✗ | Yalnızca belirsizlik; sızınca açılır |
Scope to user (AND owner_id) |
✓ | Basit, sağlam; genelde tercih |
| Nesne üzerinde policy/voter | ✓ | Merkezî, test edilebilir |
| Dolaylı referans (per-user map) | Kısmen | Yetki hâlâ gerekir; ek katman |
| UUID + yetki kontrolü | ✓ | Yetki çözer; UUID derinlik katar |
Dolaylı referans haritalama: Bir teknik, gerçek kimlikleri istemciye hiç vermeyip oturum başına opak tanıtıcılara eşlemektir (item_a → gerçekte 1002, yalnızca bu kullanıcı için). Bu numaralandırmayı zorlaştırır ama asıl çözüm değildir; yetki kontrolü yine gerekir. Ek katman olarak değerlidir.
Performans: Sahiplik koşulu (AND owner_id = ?) indeksliyse maliyeti sıfıra yakındır; hatta sonuç kümesini daralttığı için bazen daha hızlıdır. Nesne üzerinde yetki, tipik olarak bir alan karşılaştırmasıdır. Güvenlik kazancı maliyetin çok üzerindedir.
10. Gerçek Hayat Senaryosu
Kurgu — bir telemedicine (uzaktan sağlık) uygulaması. Hastalar /api/appointments/{id} uç noktasından randevu detaylarını (doktor notları, reçeteler, tanılar) görüntülüyor. Uç nokta kimlik doğrulaması istiyor ama nesne-düzeyi sahiplik kontrolü yapmıyor: giriş yapmış herhangi bir hasta, id'yi değiştirerek başka hastaların tıbbi kayıtlarına erişebiliyor. Kimlikler sıralı olduğundan, bir saldırgan tüm hasta randevularını otomatik toplayabiliyor — sağlık verisi için felaket (yasal olarak da KVKK/HIPAA/GDPR ihlali). Geliştirici "UUID'ye geçelim" diye düşünüyor ama bu yalnızca numaralandırmayı yavaşlatır; sızan bir UUID hâlâ erişim verir. Doğru çözüm: her randevu erişiminde WHERE patient_id = :currentUser veya nesne üzerinde sahiplik kontrolü. Dersler: (1) kimlik doğrulama tek başına yetmez; nesne-düzeyi yetkilendirme şart; (2) UUID belirsizliktir, güvenlik değil; (3) sıralı kimlik ölçeği büyütür ama kök neden yetki eksikliğidir.
11. Gerçek Vaka Analizi — First American Financial (2019, ~885 milyon kayıt)
KrebsOnSecurity, TechCrunch, SecurityWeek ve şirket açıklamasıyla doğrulanmıştır. Tarihin en büyük IDOR olaylarından biridir.
Özet. Mayıs 2019'da, Fortune 500 emlak sigortası devi First American Financial'ın web sitesinin, yaklaşık 885 milyon hassas belgeyi — banka hesap numaraları, banka ekstreleri, ipotek kayıtları, vergi belgeleri, havale makbuzları, sosyal güvenlik numaraları ve ehliyet fotoğrafları — internete açık biçimde ifşa ettiği ortaya çıktı. Belgeler 2003'e kadar uzanıyordu. Açığı emlak geliştiricisi Ben Shoval fark etti ve gazeteci Brian Krebs ile birlikte doğruladı; şirket 24 Mayıs 2019'da harici erişimi kapattı.
Teknik neden — IDOR'un en saf hâli. First American'ın belge bağlantıları, dokuz haneli sıralı bir kayıt numarası içeriyordu. Bir kullanıcı, kendisine ait geçerli bir belge bağlantısındaki numarayı bir artırıp azaltarak başka kişilerin belgelerine erişebiliyordu. En eski belge 000000075 (2003 tarihli bir işlem) idi; numara ileri gittikçe belgeler güncele yaklaşıyor, 885.000.000+ değerine kadar uzanıyordu. Kritik olan: hiçbir kimlik doğrulama gerekmiyordu. Belge URL'sini bir kez bilen (örneğin First American'dan e-posta ile belge bağlantısı almış herkes) tüm veri kümesini gezebiliyordu. Bu, "doğrudan nesne referansı + yetki kontrolü yokluğu" tanımının ta kendisidir.
İki dersi birlikte gösterir: (1) sıralı kimlikler numaralandırmayı önemsizleştirir — +1 ile bir sonraki kayıt; ama (2) asıl kök neden yetki/kimlik doğrulama eksikliğidir. Kimlikler UUID olsaydı bile, belge bağlantıları e-postayla paylaşıldığı ve yetki kontrolü olmadığı için sızıntı yine mümkündü — yalnızca kaba numaralandırma zorlaşırdı. Doğru çözüm, her belge erişiminde "bu kişi bu belgeye yetkili mi?" sorusunu sormaktı.
Etki. Yaklaşık 885 milyon belgenin (arşiv kanıtlarına göre en az Mart 2017'den beri) ifşası; belgelerin bir kısmı arama motorlarınca da önbelleğe alınmıştı. First American bunu bir "tasarım kusuru" olarak nitelendirip harici erişimi kapattı, olay müdahale uzmanları getirdi ve düzenleyicilere bildirdi. Olay, ABD'de ilgili siber güvenlik düzenlemeleri kapsamında dikkat çeken erken vakalardan biri oldu ve düzenleyici yaptırım/incelemeye konu oldu.
Çıkarılacak dersler: 1. IDOR'un çözümü yetkilendirmedir, gizli kimlik değil. Her nesne erişiminde sahiplik/yetki kontrolü yapılmalı; UUID yalnızca ek bir belirsizlik katmanıdır. 2. Sıralı kimlikler ölçeği patlatır. Numaralandırılabilir referanslar, tek bir açığı kitlesel sızıntıya çevirir. 3. IDOR sessizdir. Meşru isteklerden ayırt edilemediğinden aylarca fark edilmeden sürebilir; bu yüzden önleme (kod düzeyinde kontrol) tespiti beklemekten çok daha kritiktir.
12. Detection
Kod incelemede: Nesne kimliğini istemciden alıp sahiplik kontrolü olmadan sorgulayan yerleri arayın:
# İstemci kimliğiyle sorgu, owner/user koşulu olmadan
grep -rnE 'WHERE (id|uuid) *= *[?$:]' src/ | grep -viE 'owner|user_id|account'
grep -rnE '\$_(GET|POST|REQUEST)\[.(id|user_id|file|uuid).\]' src/
grep -rn 'findOrFail\|::find(' src/ # ardından authorize var mı?
Her nesne erişimi için: sahiplik sorguya dahil mi (AND owner_id) ya da nesne üzerinde authorize var mı? Hedef kullanıcı oturumdan mı geliyor?
SAST: IDOR, veri akışından çok iş mantığına bağlı olduğundan SAST için zordur; "istemci kimliğiyle sorgu + eksik sahiplik koşulu" örüntülerini kısmen yakalar. Yanlış-negatif oranı yüksektir; insan incelemesi ve DAST tamamlayıcıdır.
DAST: IDOR tespitinin en güçlü yöntemi çok-hesaplı testtir: A hesabıyla oluşturulan bir nesneye B hesabıyla (ve kimlik doğrulamasız) erişmeyi dene. Sıralı kimlik numaralandırmasını otomatik yoklar. OWASP API testinde BOLA için standart yaklaşım budur.
Loglar/SIEM: Tek bir oturumun/IP'nin çok sayıda farklı nesne kimliğine sıralı erişimi (numaralandırma imzası); bir kullanıcının kendi olmayan kaynaklara erişimi (owner_id uyuşmazlığı loglanıyorsa); yanıt boyutu/durum örüntüleri. "Aynı kullanıcı, kısa sürede artan ID'lerle çok sayıda kaynak" en güçlü IDOR sinyalidir.
13. Prevention
- Her nesne erişiminde yetki: Scope to user (
AND owner_id = :current) veya nesne üzerinde policy/voter. İstisnasız. - Kimlik oturumdan: Hedef kullanıcı/sahip asla istekten alınmaz.
- Deny by default + complete mediation: Her erişim ayrı denetlenir (Bölüm 3, 14).
- UUID'yi ek katman say: Numaralandırmayı zorlaştırır ama yetki kontrolünün yerine geçmez.
- Dolaylı referans (opsiyonel): Oturum başına opak tanıtıcılar; ek belirsizlik.
- 404 tercih et: Yetkisiz erişimde varlık sızıntısını önlemek için "yok" dönmeyi değerlendir.
- Çok-hesaplı test: IDOR için otomatik iki-hesaplı erişim testlerini CI'a ekle.
- Threat modeling: Her nesne akışını "başkası bu kimliği değiştirirse ne olur?" sorusuyla incele (Bölüm 2).
14. Mitigation
- Acil: Etkilenen uç noktalara sahiplik kontrolü ekle (scope to user); mümkünse geçici olarak sıralı kimlik uç noktalarını kısıtla/kapat; WAF'ta numaralandırma hız sınırı.
- Geçici: Loglardan numaralandırma/yetkisiz erişim kapsamını belirle; ifşa olan veriyi ve etkilenen kullanıcıları tespit et; veri ihlali bildirim yükümlülüklerini (KVKK/GDPR) değerlendir.
- Kalıcı: Tüm nesne erişimlerini policy/voter veya scope-to-user ile sağlamlaştır; çok-hesaplı testler ekle; sıralı kimlikler + yetki eksikliği kalıbını kod tabanında toplu ara.
15. Checklist
- [ ] Her nesne erişimi sahiplik/yetki kontrolü yapıyor mu (scope-to-user veya policy)?
- [ ] Hedef kullanıcı/sahip oturumdan mı alınıyor (istekten değil)?
- [ ] İstemciden gelen her nesne kimliği (URL, gövde, çerez, JSON) kontrol ediliyor mu?
- [ ] UUID kullanımı yetki kontrolünün yerine geçmiyor, üstüne mi ekleniyor?
- [ ] Yazma/silme işlemleri de sahiplik kontrolünden geçiyor mu (okuma kadar kritik)?
- [ ] Yetkisiz erişimde varlık sızıntısı önleniyor mu (404 vs 403)?
- [ ] Çok-hesaplı otomatik IDOR testleri var mı?
- [ ] Farklı HTTP fiilleri/API sürümleri tutarlı biçimde korunuyor mu?
16. Laboratuvar
Lab 15.1 — Klasik IDOR. İki hesaplı izole bir uygulama kur; A hesabıyla bir kaynak oluştur, B hesabıyla id'yi değiştirerek A'nın kaynağına eriş. Sonra AND owner_id = :current ekleyip erişimin kapandığını doğrula.
Lab 15.2 — Numaralandırma. Sıralı kimlikli bir uç noktada, kimliği artırarak birden çok kayda eriş (kendi test verinle). Kaç istekte tüm veriyi topladığını gözlemle; kök nedenin kimlik değil yetki olduğunu yaz.
Lab 15.3 — UUID yanılgısı. UUID'li ama yetkisiz bir uç nokta kur; UUID'yi "sızmış" gibi başka bir hesaba verip erişimin yine açık olduğunu göster. Yetki kontrolü ekleyip düzelt.
Lab 15.4 — Kimlik istekten mi oturumdan mı. Hedef kullanıcıyı $_POST['user_id']'den alan bir güncelleme yaz; başkasının profilini değiştir. Oturumdan almaya çevirip düzelt.
17. Quiz
- IDOR'un tek cümlelik tanımı nedir? "Insecure" kelimesi neyi işaret eder?
- IDOR, Bölüm 14'teki hangi erişim türüdür (dikey mi yatay mı)? BOLA ile ilişkisi nedir?
- "Doğrudan nesne referansı" tek başına neden kötü değildir? Onu güvensiz yapan nedir?
- UUID'ye geçmek IDOR'u neden çözmez? Belirsizlik ile güvenlik farkı nedir?
- Nesne kimliği hangi taşıyıcılardan gelebilir? Neden hepsi kontrol edilmelidir?
- "Scope to user" ve "nesne üzerinde yetki" yöntemlerini açıklayın.
- Hedef kullanıcı neden istemciden değil oturumdan alınmalıdır?
- Sıralı kimlikler IDOR'un etkisini nasıl büyütür? Kök nedeni değiştirir mi?
- First American vakası, "IDOR'un çözümü gizli kimlik değil yetkilendirmedir" dersini nasıl kanıtlar?
- IDOR neden "sessiz" bir açıktır ve bu tespit/önleme dengesini nasıl etkiler?
- Yazma IDOR'u neden okuma IDOR'undan daha yıkıcı olabilir?
- IDOR tespitinde neden çok-hesaplı DAST gereklidir; SAST neden yetersiz kalır?
18. Kaynakça
- OWASP, API Security Top 10 — API1:2023 Broken Object Level Authorization (BOLA).
- OWASP, Insecure Direct Object Reference Prevention Cheat Sheet; Authorization Cheat Sheet.
- MITRE, CWE-639: Authorization Bypass Through User-Controlled Key; CWE-284: Improper Access Control.
- KrebsOnSecurity, First American Financial Corp. Leaked Hundreds of Millions of Title Insurance Records (24 Mayıs 2019).
- TechCrunch ve SecurityWeek, First American IDOR olay raporları.
- Laravel Authorization (Policies) ve Symfony Security Voters dokümantasyonu (nesne düzeyi yetki).