Mert Özen Her Satırda Daha İleri
Güvenlik Web Güvenliği (OWASP Top 10) — #01

Web Güvenliğine Giriş: OWASP Top 10:2025 Nedir, Nasıl Okunur?

Mert Özen 6 Kas 2026 9 dk 5 görüntülenme
Web Güvenliğine Giriş: OWASP Top 10:2025 Nedir, Nasıl Okunur?

Güvenlik neden sonradan eklenen bir özellik olamaz? Başka bir müşterinin siparişini döndüren küçük bir endpoint'le başlıyor, CIA üçlüsünü ve saldırı yüzeyini, OWASP'ı ve Top 10'un neden bir standart değil farkındalık belgesi olduğunu, listenin veri ve anketle nasıl hazırlandığını ve 2025 listesinin on kategorisini görüyoruz.

Sürüm notu: Bu yazı OWASP Top 10:2025'e göre yazılmıştır; kodlar ASP.NET Core 10 (.NET 10) ile denenmiştir.

Önce Tahmin Et

Bir kitapçı uygulaması yazıyorsun. Müşteri siparişinin durumunu görebilsin diye şu endpoint'i ekledin. Kod derleniyor, testler geçiyor, Alan kendi siparişini sorunsuz görüyor:

var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();

List<Order> orders =
[
    new(1, "alan", "Clean Code", 1),
    new(2, "grace", "The Pragmatic Programmer", 2)
];

// "Kendi siparişimi göster" endpoint'i
app.MapGet("/orders/{id:int}", (int id) =>
{
    Order? order = orders.FirstOrDefault(o => o.Id == id);
    return order is null ? Results.NotFound() : Results.Ok(order);
});

app.Run();

record Order(int Id, string Customer, string Book, int Quantity);

Alan'ın siparişinin numarası 1. Alan adres çubuğundaki 1'i 2 yaparsa ne olur? Bir saniye düşün, sonra çıktıya bak:

$ curl -i http://localhost:5101/orders/1
HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8
Date: Fri, 06 Nov 2026 18:58:10 GMT
Server: Kestrel
Transfer-Encoding: chunked

{"id":1,"customer":"alan","book":"Clean Code","quantity":1}

$ curl -i http://localhost:5101/orders/2
HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8
Date: Fri, 06 Nov 2026 18:58:10 GMT
Server: Kestrel
Transfer-Encoding: chunked

{"id":2,"customer":"grace","book":"The Pragmatic Programmer","quantity":2}

Grace'in siparişi geldi. Uygulama kimin sorduğunu hiç merak etmedi. Kodda bir syntax hatası yok, bir exception yok, log'da kırmızı bir satır yok. Fonksiyonel açıdan endpoint "çalışıyor". Güvenlik açısından ise OWASP listesinin bir numaralı kategorisine, Broken Access Control'e birebir uyan bir zafiyet var. Bu seri, bu tür hataları kod yazarken görebilmek için var.

Güvenlik Neden Sonradan Eklenemez?

Projelerde sık duyulan bir cümle var: "Önce özellikleri bitirelim, güvenliğe yayından önce bakarız." Bu cümle güvenliği, sonradan takılan bir modül gibi düşünüyor. Oysa yukarıdaki hata bir modül eksikliği değil. Endpoint'in imzasında kullanıcı kimliği yok, veri katmanındaki sorguda sahiplik koşulu yok. Düzeltmek için o endpoint'e, sorguya ve muhtemelen o endpoint'i çağıran istemci koduna geri dönmen gerekiyor. Aynı kalıpla yazılmış elli endpoint varsa elli yere dönüyorsun.

Bir binayı düşün. Yangın merdiveni, kapı genişlikleri ve elektrik tesisatı proje aşamasında çizilir. Bina bittikten sonra yangın merdiveni eklemek mümkündür ama pahalıdır, çirkindir ve çoğu zaman tam oturmaz. Yazılımda da kimlik doğrulama (authentication), yetkilendirme (authorization), input validation ve hata yönetimi gibi kararlar ilk endpoint'le birlikte verilir. Sonradan eklendiğinde ya eksik kalır ya da bir yerde unutulur.

CIA Üçlüsü ve Saldırı Yüzeyi

Güvenlikte "neyi koruyoruz?" sorusunun klasik cevabı üç kelimedir ve baş harfleriyle CIA üçlüsü diye anılır. Gizlilik (confidentiality): veriyi yalnız görmesi gereken kişi görür. Bütünlük (integrity): veriyi yalnız değiştirmesi gereken kişi, izin verilen biçimde değiştirir. Erişilebilirlik (availability): sistem, ihtiyaç duyulduğunda çalışır durumdadır.

Açılıştaki örnek gizliliği bozuyor: Alan, Grace'in siparişini görüyor. Aynı kalıpta bir PUT /orders/2 endpoint'i olsaydı bütünlük de giderdi; Alan, Grace'in siparişindeki adet sayısını değiştirebilirdi. Sınırsız sayıda istek kabul eden bir arama endpoint'i ise erişilebilirliği tehdit eder; tek bir istemci veritabanını meşgul edip herkesi bekletebilir. Bir zafiyeti okurken "bu üçünden hangisini bozuyor?" diye sormak, riskin büyüklüğünü anlamanın en hızlı yoludur.

İkinci temel kavram saldırı yüzeyi (attack surface): uygulamanın dış dünyadan veri kabul ettiği ya da dış dünyaya veri verdiği her nokta. Her endpoint, her query string parametresi, her header, her cookie, yüklenen her dosya, okunan her dış servis cevabı bu yüzeyin parçasıdır. Güvenliğin ilk ve en ucuz adımı yüzeyi küçültmektir: kullanılmayan şeyi kapat, kaldır, hiç açma.

OWASP ve Top 10: Standart Değil, Farkındalık Belgesi

OWASP, uygulama güvenliği üzerine açık kaynak projeler yürüten, kâr amacı gütmeyen bir vakıf: OWASP Foundation. Belgeleri, araçları ve rehberleri herkese ücretsiz açıktır. En bilinen projesi OWASP Top 10, yani web uygulamalarındaki en kritik risk kategorilerinin listesi. Yanında Cheat Sheet Series (konu konu pratik rehberler), ASVS (Application Security Verification Standard) ve API Security Top 10 gibi projeler de var; serinin son yazısında bunlara ayrıca bakacağız.

Top 10 hakkında en önemli bilgi, ne olmadığıdır. OWASP kendisi Top 10'u bir farkındalık belgesi (awareness document) olarak tanımlar. "Top 10 uyumluyuz" diye bir sertifika yoktur ve listede olmayan bir zafiyet, önemsiz olduğu için orada değildir. Liste, en sık görülen ve en çok zarar veren kategorileri geliştiricinin gözüne sokmak için hazırlanır. Bir uygulamayı sistematik olarak doğrulamak istersen OWASP'ın önerdiği belge ASVS'dir; güncel kararlı sürümü ASVS 5.0.0, 30 Mayıs 2025'te yayımlandı.

Liste Nasıl Hazırlanıyor?

Top 10 bir anket sonucu ya da birkaç uzmanın sezgisi değil. 2025 sürümü, OWASP Top 10'un sekizinci baskısı. Arkasında, güvenlik firmalarının ve kuruluşların bağışladığı test verisi var; 2025'in veri seti 2,8 milyondan fazla uygulamayı kapsıyor. Bulgular CWE (Common Weakness Enumeration) ile sınıflandırılıyor. CWE, zafiyet türlerinin MITRE tarafından tutulan ortak sözlüğü: CWE-89 SQL injection, CWE-79 XSS, CWE-639 da açılıştaki türden, kullanıcının kontrol ettiği bir key ile yetkilendirmenin atlatılması.

Her Top 10 kategorisi birden fazla CWE'yi bir araya toplar. 2025'te on kategori toplam 248 CWE'yi kapsıyor; örneğin A01 Broken Access Control altında 40 CWE var. Kategorilerin sekizi veriden geliyor. İkisini, A03 Software Supply Chain Failures ve A09 Security Logging and Alerting Failures'ı ise topluluk anketi seçti. Anketin sebebi basit: test verisi, otomatik araçların bugün kolayca bulduğu şeyleri gösterir. Tedarik zinciri saldırıları ya da eksik loglama gibi konular verinin henüz iyi yakalayamadığı ama sahada canı yakan riskler.

2021'den beri kategoriler mümkün olduğunca kök nedene (root cause) göre adlandırılıyor, semptoma göre değil. "Hassas veri ifşası" bir sonuçtur; o sonuca götüren kök neden çoğu zaman yanlış ya da eksik kullanılan kriptografidir. Bu yüzden 2017'deki Sensitive Data Exposure, 2021'de Cryptographic Failures adını aldı. Bu evrimi serinin son blokunda ayrıca konuşacağız.

OWASP Top 10:2025'e Kuşbakışı

2025 listesi Aralık 2025'in sonunda nihai hâline geldi. Her kategoriyi kendi yazısında açacağız; şimdilik bir cümleyle:

A01:2025 Broken Access Control (bozuk erişim kontrolü): kullanıcının yetkisi olmayan veriye ya da işleve ulaşması. Açılıştaki örnek tam olarak bu. 2025'te SSRF de bu kategoriye katıldı.

A02:2025 Security Misconfiguration (güvenlik yanlış yapılandırması): Production'da açık kalan ayrıntılı hata sayfaları, varsayılan ayarlar, eksik security header'lar. XXE de burada.

A03:2025 Software Supply Chain Failures (yazılım tedarik zinciri hataları): kullandığın paketler, build ve dağıtım hattı üzerinden gelen riskler.

A04:2025 Cryptographic Failures (kriptografik hatalar): zayıf algoritmalar, düz metin parola, tahmin edilebilir rastgele sayılar, şifrelenmeden taşınan veri.

A05:2025 Injection: kullanıcı verisinin SQL, komut ya da HTML gibi bir dilin içine kod olarak karışması. SQL injection ve XSS bu kategoride.

A06:2025 Insecure Design (güvensiz tasarım): kod doğru yazılsa bile tasarımın kendisinden gelen açıklar; negatif adetli sipariş, sınırsız deneme hakkı gibi.

A07:2025 Authentication Failures (kimlik doğrulama hataları): brute force'a açık giriş, zayıf parola kuralları, yanlış yönetilen session ve token'lar.

A08:2025 Software or Data Integrity Failures (yazılım ya da veri bütünlüğü hataları): doğrulanmadan güvenilen kod ve veri; insecure deserialization, mass assignment.

A09:2025 Security Logging and Alerting Failures (güvenlik loglama ve alarm hataları): saldırıyı fark etmeni sağlayacak log'un ya da alarmın olmaması, log'a yanlış şeylerin yazılması.

A10:2025 Mishandling of Exceptional Conditions (istisnai durumların yanlış yönetimi): 2025'in yeni kategorisi. Hata anında "fail open" davranan, stack trace sızdıran ya da yarım kalan işlemi geri almayan kod.

Etik Sınır ve Serinin Kurgusu

Bu seri savunma amaçlı. Her saldırıyı yalnız kendi bilgisayarında çalışan lab uygulamasına, localhost'a karşı, sorunu kanıtlayan en küçük örnekle göstereceğim ve her gösterimin hemen ardından düzeltmesi gelecek. Bu teknikleri yalnız sahibi olduğun ya da yazılı izin aldığın sistemlerde dene. Başkasının sistemine izinsiz denemek, ne kadar "masum" bir ' OR 1=1 -- olursa olsun, çoğu ülkede suçtur. Örneklerdeki parola ve anahtarlar da açıkça sahte olacak: dev-only-... ile başlayan değerler.

Serinin ilk bloku, 1–17. yazılar, kemik yapı. Önce bir sonraki yazıda lab uygulamamızı, ASP.NET Core 10 ile yazılmış küçük bir "Bookstore API"yi kuracağız: users, books, orders ve reviews tabloları olan, SQLite kullanan bir minimal API. Sonra her 2025 kategorisi için aynı kalıbı izleyeceğiz: zafiyetli kod, saldırının nasıl çalıştığı, düzeltilmiş kod, ASP.NET Core ya da tarayıcının sunduğu savunma ve kısa bir kontrol listesi. 17. yazıda hepsini bir araya getireceğiz. İkinci blok, 18–21. yazılar, listenin evrimi: 2017 listesi, 2017'den 2021'e ve 2021'den 2025'e geçişler, OWASP'ın diğer projeleri.

Konular yer yer blogdaki diğer serilere değecek. SQL injection'da EF Core ve Dapper serilerindeki raw SQL ve parameter yazılarına, secret sızıntısında Git & GitHub serisine, yetkilendirme ve CORS'ta ASP.NET Core Web API serisine dönüp bakacağız. Orada "nasıl yapılır"ı gördük, burada "nasıl güvenli yapılır"a odaklanıyoruz.

Sık Düşülen Tuzaklar

İlk tuzak, "bizim uygulamayı kim hedef alır ki?" düşüncesi. Saldırıların büyük kısmı seni tanıyan birinden değil, internetteki her adresi deneyen otomatik araçlardan gelir.

İkincisi, gizliliği ID'lerin tahmin edilemezliğine bırakmak. Sıralı int yerine Guid kullanmak tahmin etmeyi zorlaştırır ama yetkilendirmenin yerini tutmaz. ID bir log'da, bir e-postada, bir paylaşılan linkte sızar; sızdığı anda kapı yine açıktır. Kontrol her zaman sunucuda, "bu kullanıcı bu kaydı görebilir mi?" sorusuyla yapılır.

Üçüncüsü, frontend'deki kontrolü güvenlik sanmak. Angular tarafında admin menüsünü gizlemek kullanıcı deneyimidir, güvenlik değildir. curl menüye bakmaz; doğrudan endpoint'e istek atar.

Dördüncüsü, Top 10'u eksiksiz bir liste sanmak. Listede olmayan bir risk de seni vurabilir. Top 10 nereden başlayacağını söyler; nerede duracağını söylemez.

Kontrol Listesi

Yeni bir endpoint yazarken kendine dört soru sor. Bu endpoint'i kim çağırabilir ve bu kural sunucuda nerede yazıyor? Gelen her input'un (route, query string, body, header, cookie) kaynağı ve sınırı ne? Bu endpoint CIA'nın hangisini bozabilir: başkasının verisini gösterebilir mi, değiştirebilir mi, sistemi meşgul edebilir mi? Hata olduğunda istemciye ne dönüyor ve log'a ne yazılıyor?

Proje düzeyinde de saldırı yüzeyini düzenli aralıklarla gözden geçir: kullanılmayan endpoint'leri, Production'da açık kalmış geliştirme araçlarını ve projede duran ama kullanılmayan paketleri kaldır.

Küçük Bir Deneme

★☆☆ Yukarıdaki küçük projeyi dotnet new web ile kendin oluştur, dotnet run --urls http://localhost:5101 ile çalıştır ve iki curl -i isteğini tekrarla. Sonra listeye üçüncü bir sipariş ekle ve onu da başka bir müşterinin gözüyle oku.

★★☆ Çalıştığın bir projeden üç endpoint seç. Her biri için CIA üçlüsünden hangisini bozabileceğini ve OWASP Top 10:2025'teki hangi kategoriye en çok yaklaştığını bir cümleyle yaz.

★★★ Aynı projenin saldırı yüzeyini çıkar: route'ların listesini, okunan header ve cookie'leri, yüklenen dosya türlerini ve çağrılan dış servisleri bir sayfaya yaz. Bu sayfayı serinin sonunda tekrar açacağız.

Bir sonraki yazıda lab'ı kuruyoruz: SQLite kullanan Bookstore API'yi ayağa kaldıracak, HTTP'yi güvenlik gözüyle okumayı (method, status code, header, cookie) curl -i ile çalışacak, Development ile Production ortamı arasındaki farkı ve HTTPS geliştirme sertifikasını göreceğiz.