Selam TurkTeam, BlueTornado yazıyor.
Broken Access Control, OWASP Top 10 2021 listesinde A01 olarak birinci sıradaydı. Altındaki en sık pratik bulgulardan biri de IDOR (Insecure Direct Object Reference). Bu konuda IDOR'un ne olduğunu, Broken Access Control ile ilişkisini, labda nasıl güvenli test edileceğini ve sunucu tarafı korunmayı anlatıyorum.
Konuda Anlatılacaklar
- Broken Access Control ve IDOR nedir?
- Yatay / dikey yetki karışıklığı
- Lab ortamı: Juice Shop ve basit demo API
- Tespit adımları: parametre manipülasyonu
- Korunma: yetki kontrolleri, dolaylı referanslar
- İleri seviye: mass assignment, GraphQL, BOLA
- Kaynakça ve yasal uyarı
1) Teori: Erişim Kontrolü Bozulunca Ne Olur?
Erişim kontrolü iki soruya cevap verir: "Bu kullanıcı kim?" (kimlik doğrulama) ve "Bu işlem / nesne için yetkisi var mı?" (yetkilendirme). Broken Access Control, ikinci sorunun atlanması veya yanlış cevaplanmasıdır.
IDOR: Uygulamanın iç nesneye (sipariş, dosya, mesaj) kullanıcı kontrollü bir kimlikle (id, uuid, dosya adı) doğrudan referans vermesi ve sahiplik/yetki kontrolü yapmaması.
# Tehlikeli kalıp
@app.get("/api/orders/{order_id}")
def get_order(order_id: int):
# Sadece login kontrolü var, sahiplik yok
return db.orders.get(order_id)# Doğru yönde
@app.get("/api/orders/{order_id}")
def get_order(order_id: int, user=Depends(current_user)):
order = db.orders.get(order_id)
if order is None or order.owner_id != user.id:
raise HTTPException(404) # veya 403
return orderIDOR yalnızca sayısal id'lerde olmaz. Tahmin edilebilir dosya yolları, e-posta adresleri, hesap numaraları da nesne referansı olabilir.
Alıntı:UUID kullanmak IDOR'u "çözmez". Keşfi zorlaştırabilir; yetki kontrolü olmadan bilinmeyen UUID hâlâ başkasının verisine açılan kapıdır (ör. sızıntı, referrer, bildirim linki).
2) Yatay ve Dikey Erişim
- Yatay (horizontal): Aynı roldeki A kullanıcısı, B kullanıcısının kaynağına erişir (klasik IDOR).
- Dikey (vertical): Normal kullanıcı admin işlevine erişir ().Kod:
/admin/deleteUser - Bağlam / işlev: Kullanıcı kendi siparişini görebilir ama "iade onayla" gibi ayrıcalıklı işlemi yapamamalıdır.
# Dikey örnek (kavramsal)
POST /api/admin/users/42/role {"role":"admin"}
# Rol kontrolü yoksa Broken Access Control3) Lab Ortamı
docker pull bkimminich/juice-shop
docker run --rm -p 3000:3000 bkimminich/juice-shopJuice Shop'ta sepet, geri bildirim ve kullanıcı challenge'larında erişim kontrolü zafiyetleri bilinçli olarak vardır. Spoiler vermeden: kendi hesabınızla oluşturduğunuz nesnelerin kimliklerini not alıp, başka hesapla aynı kimliğe istek atmayı deneyin (yalnızca localhost).
Basit bir yerel demo için:
# Flask iskeleti (kasıtlı zayıf - sadece lab)
orders = {1: {"owner": "ali", "item": "kitap"}, 2: {"owner": "ayse", "item": "kalem"}}
@app.get("/orders")
def get(id: int):
return orders[id] # sahiplik yok![center][/center]
4) Kavram Referansı
Direct object reference:
GET /invoices/18442.pdf
GET /api/v1/messages/9921Indirect reference map: Kullanıcıya geçici, oturuma bağlı rastgele anahtar vermek. Yine de sunucuda yetki doğrulanmalıdır.
# Kavramsal eşleme
session_refs["a8f0..."] = {"type":"invoice", "id":18442, "owner": user.id}Forced browsing: Auth gerektiren URL'lerin tahmin edilerek gezilmesi.
/admin/dashboard
/api/internal/metricsCORS yanlış yapılandırması: Access-Control-Allow-Origin: * ve credentials birlikte veya aşırı geniş origin listesi, tarayıcıdan yetkisiz okumayı kolaylaştırabilir.
5) Tespit: Adım Adım (Yasal Lab)
Adım 1 - İki hesap oluşturun. A ve B. A ile kaynak yaratın (sipariş, not, dosya).
Adım 2 - İstekleri kaydedin. Burp / DevTools ile
order_iduserIddoc# Örnek istek
GET /api/orders/105 HTTP/1.1
Cookie: session=A_SESSIONAdım 3 - Kimliği değiştirin. 105 yerine B'nin veya A'nın diğer kaydını koyun; oturum A'da kalsın.
GET /api/orders/106 HTTP/1.1
Cookie: session=A_SESSIONAdım 4 - Yanıtı yorumlayın.
- 200 + B'nin verisi -> yatay IDOR güçlü aday
- 403/404 -> kontrol var (yine de başka uçları deneyin)
- 301 ile başka yere gitmek -> mantığı anlayın
[center][/center]
Adım 5 - Metotları deneyin. GET güvenli görünürken PUT/DELETE/PATCH açık kalmış olabilir.
PUT /api/orders/106
{"status":"refunded"}Adım 6 - Encoding / tip oyunları.
106106.0[106]{"id":106}6) Korunma
- Her istekte sunucu tarafı yetki kontrolü (deny by default)
- "Bu nesne bu kullanıcıya mı ait?" sorusunu merkezi bir policy katmanında sorun
- Sadece UI'da butonu gizlemek yetmez
- Admin işlevlerini ayrı rol ve mümkünse ayrı ağ/segment ile koruyun
- Loglayın: access.denied olayları
- Otomatik test: A kullanıcısı B kaynağına 403 bekleyen entegrasyon testleri
# Pseudo-policy
def authorize(user, action, resource):
if user.role == "admin" and action in ADMIN_ACTIONS:
return True
if resource.owner_id == user.id and action in OWNER_ACTIONS:
return True
return False# Django örneği
class OrderDetail(LoginRequiredMixin, UserPassesTestMixin, DetailView):
def test_func(self):
return self.get_object().owner_id == self.request.user.id[center][/center]
7) İleri Seviye
BOLA (Broken Object Level Authorization): OWASP API Top 10'da API'ler için IDOR'un karşılığıdır. API güvenliği konusunda ayrıca ele alınacak.
Mass assignment / bağlama: Kullanıcının
{"role":"admin"}# Tehlikeli
user.update(request.json)
# Güvenli: allowlist
user.update({k: request.json[k] for k in ("name", "bio")})GraphQL: Nesne id'leri ile başka kullanıcı kayıtlarını çekmek; field-level authorization gerekir.
Batch / IDOR otomasyonu: Intruder ile id bruteforce yalnızca yetkili labda; üretimde rate limit ve izleme şarttır.
# Rapor dili
Bulgu: IDOR / Broken Access Control (CWE-639)
Endpoint: GET /api/orders/{id}
Kanıt: Kullanıcı A, kullanıcı B siparişini 200 ile okudu
Öneri: sahiplik kontrolü + test otomasyonu8) Sonuç
IDOR, Broken Access Control ailesinin görünür yüzüdür. UUID, "gizli URL" veya sadece frontend kontrolü yetmez. Sunucuda her nesne erişiminde yetki sorun; A/B hesap testlerini CI'ya ekleyin.
Kaynakça
- OWASP Top 10 2021 A01
- OWASP IDOR Prevention Cheat Sheet
- OWASP API Top 10 - BOLA
- CWE-639
- OWASP Juice Shop
Yasal Uyarı
Erişim kontrolü testleri yalnızca kendi uygulamalarınızda veya yazılı yetki kapsamındaki pentestlerde yapılmalıdır. Başkasının hesabına veya sistemine izinsiz erişim denemesi TCK 243-245 kapsamında suç oluşturabilir. Eğitim amaçlıdır; sorumluluk uygulayana aittir.