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

OWASP Top 10: 2017'den 2021'e, Semptomdan Kök Nedene

Mert Özen 6 Kas 2026 7 dk 4 görüntülenme
OWASP Top 10: 2017'den 2021'e, Semptomdan Kök Nedene

2017 listesinin 2021'de nasıl yeniden kurulduğunu inceliyoruz: Sensitive Data Exposure'dan Cryptographic Failures'a, Broken Access Control'ün bir numaraya çıkışı, XSS'in Injection'a katılması, Insecure Design ve SSRF'in gelişi. Küçük bir .NET örneğiyle SQL parametresi ile HTML encoding'in aynı kök nedene verilen cevap olduğunu gösteriyor, 2021 metodolojisini rakamlarıyla anlatıyoruz.

Sürüm notu: Bu yazı OWASP Top 10:2017 ile OWASP Top 10:2021'i karşılaştırır; bugünkü karşılıklar OWASP Top 10:2025'e göre verilmiş, kod .NET 10 ile denenmiştir.

Önce Tahmin Et

2017 listesinde üçüncü sırada Sensitive Data Exposure vardı. 2021 listesinde bu adla bir madde yok. Sence kayboldu mu, başka bir kategoriye mi katıldı, yoksa yeni bir adla mı devam etti? Devam ettiyse hangi sırada?

Cevap: A02:2021 Cryptographic Failures adıyla bir basamak yukarı çıktı. Ad değişikliğinin gerekçesi bu yazının ana fikri: OWASP, "veri sızdı" demenin bir semptomu tarif ettiğini, kök nedenin ise çoğu zaman eksik ya da yanlış kriptografi olduğunu söyledi. 2021 listesini okumanın anahtarı bu bakış değişikliği. Kod örneği bu kez küçük ve tamamen savunma tarafında; yine de genel kuralı hatırlatayım: bu teknikleri yalnız sahibi olduğun ya da yazılı izin aldığın sistemlerde dene.

2021 Listesi Bir Bakışta

OWASP Top 10:2021, Eylül 2021'de yayımlandı. Proje deposunda 24 Eylül 2021 tarihli "It's been released" commit'i duruyor. Listeyi 2017'deki karşılıklarıyla birlikte okuyalım.

A01 Broken Access Control, 2017'nin A5'inden bir numaraya çıktı. A02 Cryptographic Failures, A3 Sensitive Data Exposure'ın yeni adı. A03 Injection birinciliği bıraktı ve 2017'nin A7'si olan XSS'i içine aldı. A04 Insecure Design tamamen yeni. A05 Security Misconfiguration, A6'dan bir basamak yükseldi ve 2017'nin A4'ü XXE'yi bünyesine kattı.

A06 Vulnerable and Outdated Components, A9 Using Components with Known Vulnerabilities'in yeni adı. A07 Identification and Authentication Failures, A2 Broken Authentication'ın yeni adı. A08 Software and Data Integrity Failures yeni bir kategori ve 2017'nin A8'i Insecure Deserialization'ı içine aldı. A09 Security Logging and Monitoring Failures, A10 Insufficient Logging & Monitoring'in yeni adı. A10 Server-Side Request Forgery (SSRF) ise listeye yeni girdi.

Numaralandırma da değişti: 2017'nin A1'i 2021'de A01 oldu. Küçük bir ayrıntı gibi görünüyor ama eski dokümanları ararken önemli; bir sonraki yazıda bunun için küçük bir araç yazacağız.

Semptomdan Kök Nedene

2017 kategorilerinin bir kısmı bir sonucu ("hassas veri açığa çıktı") ya da bir teknolojiyi ("XML") adlandırıyordu. 2021'de OWASP kategorileri mümkün olduğunca kök nedene göre kurdu. Bir doktor benzetmesi işe yarar: ateş bir semptomdur, tedavi ise enfeksiyona yöneliktir. "Sensitive Data Exposure" ateşe bakıyordu; "Cryptographic Failures" enfeksiyona.

Bu yaklaşımın pratik sonucu şu: kategori adı, düzeltmenin nerede yapılacağını söylüyor. "Cryptographic Failures" dediğinde aklına TLS ayarları, parola hash'i ve anahtar yönetimi gelir. "Sensitive Data Exposure" dediğinde ise neye bakacağın belli değildi. XXE'nin Security Misconfiguration'a katılması da aynı mantık: sorun XML formatı değil, tehlikeli bir parser özelliğinin açık bırakılması.

Broken Access Control Neden Bir Numara

2017'de beşinci olan Broken Access Control 2021'de en üste çıktı ve 2025'te de orada kaldı. Benim yorumum şu: uygulamalar API'lere bölündükçe her endpoint ayrı bir kapı oldu. /orders/42 gibi tahmin edilebilir id'ler URL'de dolaşıyor, tek sayfa uygulamalar arayüzde butonu gizliyor ama sunucu aynı isteği hâlâ kabul ediyor. Yetkilendirme kararı her endpoint'te, sunucuda, kaynağın kendisine bakılarak verilmezse açık kaçınılmaz.

Bu serinin 3. ve 4. yazılarında bunu Bookstore API üzerinde gördük: başka bir kullanıcının siparişini okumak (IDOR), admin endpoint'inde eksik kontrol ve bu yüzden resource-based authorization. 2021'deki yükseliş, sorunun en yaygın ve en kolay gözden kaçan sorun olduğunu söylüyor.

Injection Genişliyor: XSS'in Katılması

XSS'in Injection'a katılması ilk bakışta tuhaf gelebilir; biri veritabanında, diğeri tarayıcıda olur. Ama kök neden aynı: veri, bir yorumlayıcıya kodun parçası olarak gidiyor. Savunma da aynı kalıptan çıkıyor: veriyi kodla karıştırma, gittiği bağlamın kurallarıyla taşı.

using System.Text.Encodings.Web;
using Microsoft.Data.Sqlite;

using SqliteConnection connection = new("Data Source=:memory:");
connection.Open();
using (SqliteCommand setup = connection.CreateCommand())
{
    setup.CommandText = """
        CREATE TABLE reviews (id INTEGER PRIMARY KEY, author TEXT, body TEXT);
        INSERT INTO reviews (author, body) VALUES ('ada', 'Great book'), ('alan', 'Too long');
        """;
    setup.ExecuteNonQuery();
}

string author = "ada";
string body = "<b>Great</b> book";

// SQL: değer sorgu metninin parçası olarak değil, parametre olarak gider
using (SqliteCommand query = connection.CreateCommand())
{
    query.CommandText = "SELECT COUNT(*) FROM reviews WHERE author = $author";
    query.Parameters.AddWithValue("$author", author);
    Console.WriteLine($"SQL rows for '{author}': {query.ExecuteScalar()}");
}

// HTML: değer, yazıldığı bağlama göre encode edilir
Console.WriteLine($"HTML output: <p>{HtmlEncoder.Default.Encode(body)}</p>");
$ dotnet run
SQL rows for 'ada': 1
HTML output: <p>&lt;b&gt;Great&lt;/b&gt; book</p>

İki durumda da kullanıcıdan gelen değer, yorumlayıcının dilbilgisine dokunamıyor. SQL tarafında parametre, değeri sorgu metninden ayrı taşıyor; HTML tarafında HtmlEncoder, <b>'yi etiket olmaktan çıkarıp metne çeviriyor. Razor'ın @ ifadesi ve Angular'ın interpolation'ı ikinci işi senin yerine yapar; Dapper ve EF Core'un parametreli API'leri birinciyi. İki savunma aynı cümleyle anlatılabildiği için tek kategori altında durmaları mantıklı.

Yeni Gelenler: Insecure Design ve SSRF

A04:2021 Insecure Design listenin en farklı maddesi oldu. Diğer kategoriler büyük ölçüde "kodda yanlış yazılan satır" iken bu madde "doğru yazılmış ama yanlış tasarlanmış özellik" diyor. Kuponu sınırsız kullandırmak, şifre sıfırlama akışında tahmin edilebilir adımlar, sınırsız deneme hakkı: kod kusursuz olsa da açık tasarımda. Kategorinin cevabı da bir kod kalıbı değil, bir süreç: threat modeling, abuse case'ler ve güvenli tasarım kalıpları. 2021'de en çok CWE'yi (40) toplayan kategori de buydu.

A10:2021 SSRF ise tersine en dar kategoriydi: tek bir CWE (CWE-918). Sunucunun, kullanıcının verdiği bir URL'ye kendisi istek atması ve bu yolla iç ağdaki kaynaklara ulaşılması. Bulut ortamlarında iç servislerin ve metadata uçlarının yaygınlaşmasıyla risk büyüdü. Bu kadar dar bir kategorinin listeye girmesinin sebebi, aşağıda göreceğimiz topluluk anketi.

Metodoloji Farkı

2021 listesi, OWASP'ın açıkladığı rakamlarla 500 binden fazla uygulamanın verisine dayanıyor. Analiz edilen CWE sayısı önceki sürümdeki yaklaşık 30'dan neredeyse 400'e çıktı. Yaklaşık 125 bin CVE, 241 farklı CWE'ye eşlendi. Kategoriler ortalama 19,6 CWE içeriyor; en dar olanı tek CWE'li A10, en genişi 40 CWE'li A04.

On kategoriden sekizi veriden, ikisi topluluk anketinden geldi: A09 Security Logging and Monitoring Failures ve A10 SSRF. Sebep basit: test verisi geçmişe bakar. Bir zafiyet türünü test araçları henüz iyi yakalamıyorsa veride az görünür; sahada çalışan insanlar ise onu çoktan yaşamış olabilir. Anket, verinin göremediğini listeye taşımanın yolu. Aynı yöntem 2025'te de devam etti; bunu bir sonraki yazıda göreceğiz.

Sık Düşülen Tuzaklar

Birincisi, ad değişikliğini içerik değişikliği sanmak. A07 Identification and Authentication Failures, 2017'nin Broken Authentication'ıyla büyük ölçüde aynı konuyu anlatıyor; ama A08 Software and Data Integrity Failures yalnız yeni bir ad değil, deserialization'ı içine alan daha geniş bir kategori. Eski bir maddeyi eşlerken adına değil içeriğine bak.

İkincisi, sıralamayı risk sıralaması sanmak. A04'ün A05'ten "daha tehlikeli" olduğu söylenemez; sıra, OWASP'ın veri ve anketle yaptığı genel bir önceliklendirme. Senin uygulaman için en önemli madde, senin tehdit modelinin söylediğidir.

Üçüncüsü, XSS'in Injection'a katılmasını "XSS önemini yitirdi" diye okumak. Önceki yazıda gördüğümüz gibi XSS bugün Injection'ın en kalabalık CWE'si.

Dördüncüsü, Insecure Design'ı bir araçla kapatmaya çalışmak. Bu kategoride SAST ya da DAST az şey bulur; tasarım toplantısında sorulan "bu özelliği nasıl kötüye kullanırım?" sorusu çok daha fazlasını.

Kontrol Listesi

2017'ye göre yazılmış bir güvenlik dokümanını güncellerken her maddeyi 2021 (ve oradan 2025) karşılığıyla eşle; Sensitive Data Exposure'ı Cryptographic Failures, XXE'yi Security Misconfiguration, XSS'i Injection, Insecure Deserialization'ı Software and Data Integrity Failures altına taşı. Numaraları yılıyla yaz. SQL'de parametre, HTML'de bağlama uygun encoding kullan; ikisini aynı kod incelemesi sorusuyla kontrol et: "veri bir yorumlayıcıya kod olarak gidiyor mu?" Yeni bir özellik tasarlarken bir abuse case listesi çıkar. Sunucunun dışarıya istek attığı her yerde SSRF'i düşün.

Küçük Bir Deneme

★☆☆ Yukarıdaki programda body değerini Tom & Jerry "quoted" yap ve HtmlEncoder'ın & ile tırnakları nasıl çevirdiğini gör. Sonra aynı değeri JavaScriptEncoder.Default.Encode ile dene ve farkı not et.

★★☆ Bookstore API'deki review endpoint'i için bir tasarım sorusu sor: aynı kullanıcı aynı kitaba kaç yorum yazabilir? Kuralı koda dök ve kuralı ihlal eden isteğin reddedildiğini gösteren bir test yaz.

★★★ Kendi projendeki ya da açık kaynak bir projedeki güvenlik dokümanını (README, threat model, PR şablonu) aç ve içindeki 2017 kategori referanslarını 2021 karşılıklarıyla eşle. Kaç tanesi yalnız ad değişikliği, kaç tanesi başka bir kategoriye taşınma?

Bir sonraki yazıda 2021'den 2025'e geçiyoruz: SSRF'in A01'e katılması, bileşen sorununun tedarik zincirine büyümesi, Misconfiguration'ın ikinciliğe çıkışı, yeni A10 ve eski numaralarla yazılmış dokümanları bir araçla güncellemek.