Henüz kariyerimin başlarındayken, bir e-ticaret sitesinin sızma testini gerçekleştiriyordum. Basit bir 'sipariş detayları' sayfası vardı. URL'de order_id=5432 gibi bir parametre gördüm. Yan sekmede kendi hesabımla giriş yapıp, bu rakamı 5431 olarak değiştirdim. Karşımda başka bir müşterinin adresi, telefon numarası ve kredi kartının son dört hanesi duruyordu. O anki heyecanla 'Buldum!' diye zıplarken, test ortamında olduğumuzu unutup gerçek veritabanı yansımasıyla çalıştığımı fark etmemiştim. O gün o veriyi kazara değiştirmekten kıl payı kurtulmuştum ama o 'bir rakamı değiştirme' hissi, web güvenliğine bakışımı sonsuza dek değiştirdi.
Bugün sizinle bu 'sessiz' ama yıkıcı açığı, yani Insecure Direct Object Reference (IDOR) ve onun amca çocukları olan iş mantığı (business logic) hatalarını konuşacağız. Neden otomatik tarayıcılar bunları görmezden gelir? Neden yazılımcılar hala bu hataya düşer? Hadi gelin, mutfağa girelim.
IDOR Nedir? Sadece Rakam Değiştirmek mi?
Aslında IDOR, en temelinde bir 'yetkilendirme' (authorization) eksikliğidir. Bir uygulama, kullanıcının talep ettiği nesneye (bir dosya, bir veritabanı kaydı, bir kullanıcı profili) gerçekten erişim hakkı olup olmadığını kontrol etmeden o nesneyi sunduğunda IDOR gerçekleşir.
Genellikle şöyle bir akış görürüz:
- Kullanıcı giriş yapar.
- Tarayıcı
https://testCompany.com/api/v1/invoice/1001adresine istek atar. - Sunucu, 1001 numaralı faturayı veritabanından çeker ve JSON olarak döner.
- Kötü niyetli kullanıcı (veya meraklı bir Red Teamer), 1001'i 1000 yapar.
- Sunucu 'Hop kardeşim, sen kimsin?' demezse, geçmiş olsun.
Neden Otomatik Araçlar Çuvallar?
DAST (Dynamic Application Security Testing) araçları XSS bulmakta harikadır; çünkü <script>alert(1)</script> gibi bir payload gönderip dönen cevapta bunu ararlar. SQL Injection bulurlar çünkü veritabanı hatasını yakalarlar. Ancak bir IDOR açığını bulmak için aracın 'iş mantığını' bilmesi gerekir. Aracın, 1001 numaralı faturanın 'Sedat'a', 1000 numaralı faturanın 'Ahmet'e' ait olduğunu ve Sedat'ın Ahmet'in verisini görmemesi gerektiğini anlaması zordur. Bu yüzden IDOR, hala manuel pentestlerin ve bug bounty avcılarının favorisidir.
Sahadan Bir Senaryo: Parametre Kurcalama (Parameter Tampering)
Sadece IDOR değil, bazen iş mantığını öyle bir kurarız ki, saldırganın tek yapması gereken sunucuya 'yalan söylemektir'. Bir keresinde bir 'Premium Üyelik' akışında şöyle bir istek yakalamıştım:
POST /api/v1/checkout HTTP/1.1
Host: testCompany.com
Content-Type: application/json
{
"product_id": "premium_plan_yearly",
"amount": "1000.00",
"currency": "TRY"
}
Buradaki hatayı görebiliyor musunuz? amount (tutar) parametresi istemci (client) tarafından gönderiliyor. Burayı "amount": "0.01" olarak değiştirip gönderdiğimde, sistem ödemeyi 1 kuruş olarak işleme almıştı. Çünkü backend, ürünün fiyatını kendi veritabanından çekmek yerine, frontend'den gelen veriye güveniyordu.
Savunma Hattı: Bu Delikleri Nasıl Kapatırız?
Şimdi biraz kod konuşalım. Genelde yapılan en büyük hata, sadece 'oturum açık mı?' kontrolü yapmaktır. Ama 'bu veriye bu kişinin erişimi var mı?' sorusu cevapsız kalır.
Hatalı Kod Örneği (Node.js/Express):
app.get('/api/invoice/:id', async (req, res) => {
// Kötü pratik: Sadece login kontrolü var (varsayalım bir middleware yapıyor)
const invoice = await db.Invoices.findByPk(req.params.id);
if (!invoice) {
return res.status(404).send('Bulunamadı');
}
// HATA: Fatura bulundu ama bu fatura bu kullanıcıya mı ait?
res.json(invoice);
});
Doğru Yaklaşım (Ownership Check):
app.get('/api/invoice/:id', async (req, res) => {
const userId = req.user.id; // JWT veya Session'dan gelen güvenilir ID
const invoiceId = req.params.id;
const invoice = await db.Invoices.findOne({
where: {
id: invoiceId,
ownerId: userId // Sorguya sahiplik şartı ekliyoruz
}
});
if (!invoice) {
// Güvenlik ipucu: 'Erişim yetkiniz yok' yerine 'Bulunamadı' dönmek
// saldırganın ID'nin var olup olmadığını anlamasını zorlaştırır.
return res.status(404).send('Fatura bulunamadı veya yetkiniz yok.');
}
res.json(invoice);
});
IDOR'dan Kaçınmak İçin Altın Kurallar
Ardışık Olmayan ID'ler Kullanın (UUID): Eğer faturanızın ID'si
101ise, bir sonrakinin102olduğunu herkes bilir. Ama550e8400-e29b-41d4-a716-446655440000gibi bir UUID kullanırsanız, saldırganın rastgele ID tahmin etmesi imkansızlaşır. (Tabii bu tek başına bir güvenlik önlemi değildir, sadece işi zorlaştırır).Dolaylı Nesne Referansları (Map): Kullanıcıya doğrudan veritabanı ID'sini göstermek yerine, o oturuma özel geçici anahtarlar oluşturabilirsiniz.
invoice_id=1yerinekey=a8jK2gibi.Her İstekte Yetki Kontrolü: 'Zaten login oldu, ne isterse yapabilir' düşüncesi güvenliğin katilidir. Her API endpoint'inde, talep edilen kaynağın sahipliğini veya erişim yetkisini (ACL - Access Control List) mutlaka kontrol edin.
Frontend'e Güvenmeyin: Fiyat, indirim oranı, kullanıcı rolü gibi kritik bilgileri asla istemciden (browser) almayın. Bunları her zaman sunucu tarafındaki güvenilir kaynaktan (SSOT - Single Source of Truth) okuyun.
İş Mantığı Hataları (Business Logic Flaws)
IDOR'un bir tık ötesi, uygulamanın tasarımındaki mantık hatalarıdır. Mesela bir şifre sıfırlama akışında, sunucu size bir OTP (tek kullanımlık şifre) gönderiyor olsun. Siz bu OTP'yi girerken, tarayıcı arka planda şöyle bir istek atıyor:
POST /verify-otp?user_id=123&otp=4567
Eğer saldırgan user_id kısmını kurbanın ID'si ile değiştirip, kendi hesabına gelen OTP'yi girerse ve sunucu sadece 'bu OTP geçerli mi?' diye bakıp, hangi kullanıcı için geçerli olduğuna bakmazsa, kurbanın hesabını ele geçirebilir. Bu bir kod hatası değil, bir düşünce/tasarım hatasıdır.
Kapanışa Doğru
Web güvenliği sadece karmaşık exploit'ler veya 0-day açıklarından ibaret değil. Çoğu zaman en büyük sızıntılar, unutulan bir where koşulu veya güvenilen bir kullanıcı parametresi yüzünden gerçekleşiyor. Biz Red Team tarafında 'acaba bu butona basınca arkada ne dönüyor?' diye her zaman kurcalarız. Sizin de savunma tarafında 'acaba kullanıcı bu ID'yi değiştirirse ne olur?' sorusunu kendinize sormanız gerekiyor.
Unutmayın, en güvenli kod, yazılmamış kod değil; her adımda 'Ya eğer...?' sorusuna cevap verebilen koddur. Bir sonraki siber güvenlik sohbetimizde görüşmek üzere, root yetkiniz bol olsun!
