July 13, 2026
Cross-Site Request Forgery (CSRF): Kullanıcının Haberi Olmadan Yapılan Saldırılar
Web Güvenliği Serisi — Bölüm 3

By Yusufbarut
18 min read
Giriş
Web uygulama güvenliği söz konusu olduğunda çoğu kişinin aklına ilk gelen saldırı türleri Cross-Site Scripting ve SQL Injection'dır. Bu iki zafiyet sınıfı, hem yaygınlıkları hem de etkilerinin görünürlüğü nedeniyle güvenlik camiasında en çok konuşulan konular arasında yer alır. Ancak bu ikisinin gölgesinde kalan, buna rağmen etkisi hiç de küçümsenmeyecek bir saldırı türü daha vardır: Cross-Site Request Forgery, kısaca CSRF.
CSRF, saldırganın kurbanın tarayıcısını kullanarak, kurbanın haberi ve rızası olmadan bir hedef sisteme istek gönderttiği bir saldırı sınıfıdır. Burada dikkat edilmesi gereken en önemli nokta şudur: CSRF saldırısında istismar edilen şey bir yazılım hatası değil, tarayıcıların ve web uygulamalarının birbirine duyduğu güvendir. Saldırgan kötü niyetli bir kod parçası enjekte etmez, veritabanı sorgusunu manipüle etmez. Bunun yerine, kurbanın oturumunu, kurbanın kendi tarayıcısı üzerinden, kurbanın kendi isteği gibi görünecek şekilde kötüye kullanır.
Bu yazı, Web Güvenliği Serisi'nin üçüncü bölümü olarak CSRF zafiyetini baştan sona, teorik temellerinden pratik sömürü tekniklerine, tespit yöntemlerinden savunma stratejilerine kadar derinlemesine ele alacak. Amacım yalnızca "CSRF nedir" sorusuna yüzeysel bir cevap vermek değil; bu zafiyetin neden hâlâ var olduğunu, neden bazı modern korumaların yeterli olmadığını ve bir geliştiricinin veya sızma testi uzmanının bu konuyu gerçekten nasıl kavraması gerektiğini anlatmak.
CSRF Neden Hâlâ Güncel?
CSRF, ilk kez 2000'li yılların başında akademik çevrelerde tartışılmaya başlanan, oldukça eski bir zafiyet sınıfıdır. Buna rağmen OWASP Top 10 listelerinde ve gerçek dünya bug bounty raporlarında hâlâ karşımıza çıkmaya devam ediyor. Bunun birkaç temel nedeni var.
Birincisi, tarayıcıların çalışma mantığı gereği, bir siteye ait çerezler, o çerezleri oluşturan domain'e giden her istekte otomatik olarak gönderilir. Bu davranış, HTTP protokolünün ve çerez mekanizmasının temel tasarımının bir parçasıdır ve kaldırılması mümkün değildir. Tarayıcı, isteğin nereden geldiğini umursamaz; önemli olan isteğin nereye gittiğidir.
İkincisi, modern web uygulamaları giderek daha karmaşık hâle geldikçe, geliştiriciler CSRF korumasını genellikle framework'lerin varsayılan davranışına bırakıyor. Bu bir yandan iyi bir şey, çünkü Django, Rails, Laravel gibi framework'ler CSRF token mekanizmalarını hazır sunuyor. Ama öte yandan, API tabanlı mimarilere, mikroservislere ve özel authentication akışlarına geçildiğinde bu varsayılan korumalar devre dışı bırakılabiliyor veya yanlış yapılandırılabiliyor.
Üçüncüsü, SameSite çerez özniteliği gibi modern tarayıcı korumaları CSRF riskini önemli ölçüde azaltmış olsa da, bu korumalar her senaryoyu kapsamıyor. Eski tarayıcı sürümleri, yanlış yapılandırılmış SameSite değerleri, subdomain'ler arası güven ilişkileri ve GET tabanlı state-changing endpoint'ler gibi durumlar CSRF'i hâlâ gerçek bir tehdit hâlinde tutuyor.
CSRF ile XSS Arasındaki Fark
CSRF ve XSS sıkça birbirine karıştırılır çünkü ikisi de tarayıcı tarafında çalışan, kurbanın oturumunu hedef alan saldırılardır. Ancak aralarındaki fark temelden farklıdır.
XSS'te saldırgan, hedef web sitesine kötü niyetli JavaScript kodu enjekte eder. Bu kod, kurbanın tarayıcısında hedef sitenin kendi origin'i içinde çalışır. Bu sayede saldırgan, kurbanın çerezlerini okuyabilir, sayfanın DOM'unu manipüle edebilir, keylogger çalıştırabilir veya kurban adına istekler gönderebilir. XSS'in gücü, saldırganın hedef origin içinde kod çalıştırabilmesinden gelir.
CSRF'te ise saldırgan hedef sitede hiçbir kod çalıştırmaz. Saldırgan kendi kontrolündeki farklı bir sitede (attacker.com gibi) bir sayfa hazırlar ve bu sayfa, kurbanın tarayıcısı üzerinden hedef siteye (bank.com gibi) bir istek tetikler. Kurbanın tarayıcısı bu isteğe hedef sitenin çerezlerini otomatik olarak ekler, çünkü tarayıcı açısından bu istek gerçekten bank.com'a gidiyordur.
Bu farkın pratik sonucu şudur: XSS ile saldırgan sunucudan gelen cevabı okuyabilir, çünkü kod hedef origin içinde çalışıyordur. CSRF ile saldırgan genellikle cevabı okuyamaz; Same-Origin Policy bunu engeller. CSRF sadece "kör" bir şekilde istek göndertebilir. Bu yüzden CSRF saldırıları genellikle state-changing işlemleri hedef alır: para transferi, şifre değiştirme, e-posta adresi güncelleme, hesap silme gibi.
Özellik XSS CSRF Kod çalıştırma Hedef origin içinde JavaScript çalıştırır Hedef origin içinde kod çalıştırmaz Cevabı okuma Genellikle okuyabilir Genellikle okuyamaz (SOP engeli) Ana istismar noktası Girdi doğrulama ve çıktı encode eksikliği Eksik veya öngörülebilir istek doğrulama Tipik hedef Veri hırsızlığı, oturum ele geçirme State-changing işlemler Ana savunma Çıktı encoding, CSP CSRF token, SameSite cookie
CSRF ile SQL Injection Arasındaki Fark
SQL Injection, tamamen farklı bir katmanda çalışan bir zafiyettir. Burada saldırgan, uygulamanın veritabanı sorgularına kullanıcı girdisi üzerinden müdahale eder. Sorgu mantığını değiştirerek yetkisiz veri okuyabilir, veri silebilir veya bazı durumlarda sunucu üzerinde komut çalıştırabilir. SQL Injection'ın gerçekleşmesi için tarayıcıya veya kurbana ihtiyaç yoktur; saldırgan doğrudan sunucuyla konuşur.
CSRF ise tamamen istemci tarafı bir zincire dayanır. Saldırının başarılı olması için mutlaka bir kurbanın, oturumu açıkken kötü niyetli sayfayı ziyaret etmesi gerekir. Sunucu tarafında hiçbir veri doğrulama açığı olmasa bile, sadece "bu isteği gerçekten kullanıcı mı gönderdi yoksa başka bir site mi tetikledi" sorusuna cevap veremiyorsa CSRF'e açık olabilir.
Özetle: SQL Injection bir veri doğrulama problemi, XSS bir çıktı encode problemi, CSRF ise bir istek kaynağı doğrulama problemidir. Üçü de OWASP Top 10'da yer almış olsa da, kök nedenleri ve istismar mekanizmaları birbirinden tamamen ayrıdır.
CSRF Nedir?
CSRF'i tam olarak anlamak için önce sahnedeki aktörleri ve aralarındaki ilişkiyi netleştirmek gerekir.
Kurban (Victim): Hedef web sitesinde geçerli bir oturumu bulunan, yani daha önce giriş yapmış ve tarayıcısında geçerli bir session çerezi taşıyan kullanıcıdır. CSRF saldırısının çalışabilmesi için kurbanın saldırı anında hedef siteye giriş yapmış olması (ya da "beni hatırla" gibi kalıcı oturum çerezine sahip olması) gerekir.
Tarayıcı (Browser): Saldırının fiilen gerçekleştiği ortamdır. Tarayıcı, bir siteye ait çerezleri o sitenin domain'ine giden her istekle birlikte otomatik olarak gönderir. Bu davranış kullanıcı deneyimini kolaylaştırmak için tasarlanmıştır, ama aynı zamanda CSRF'in temel taşını oluşturur.
Kimliği Doğrulanmış Oturum (Authenticated Session): Kullanıcının kimlik doğrulamasını tamamladıktan sonra sunucunun kullanıcıyı tanımasını sağlayan mekanizmadır. Genellikle bir session ID, bazen bir JWT token bu görevi üstlenir.
Çerezler (Cookies): Session ID'sinin tarayıcıda saklandığı ve her istekle birlikte sunucuya taşındığı mekanizmadır. CSRF'in kalbinde çerezlerin bu "otomatik ekleme" davranışı yatar.
Sunucu (Server): Gelen isteği alır, çerezdeki session ID'yi doğrular ve kullanıcıyı kimliklendirir. Sunucu, isteğin gerçekten kullanıcının bilinçli eylemiyle mi yoksa üçüncü bir sitenin tetiklemesiyle mi geldiğini ayırt edecek ek bir kontrol yapmıyorsa, isteği meşru kabul eder.
Güven İlişkisi (Trust Relationship): CSRF'in özünde yatan kavram tam olarak budur. Sunucu, "geçerli bir session çerezi taşıyan her istek, kullanıcının kendi bilinçli eylemidir" varsayımına güvenir. Bu varsayım aslında yanlıştır, çünkü çerez varlığı sadece tarayıcının kimin oturumuna ait olduğunu gösterir; isteğin gerçekten o kullanıcı tarafından, o kullanıcının isteğiyle mi gönderildiğini göstermez. CSRF saldırısı, işte tam olarak bu boşluğu istismar eder.
Not:_ CSRF'i anlatırken en sık yapılan yanlış, bu saldırıyı bir "kimlik doğrulama zafiyeti" olarak tanımlamaktır. Oysa CSRF bir yetkilendirme ve istek bütünlüğü sorunudur. Kullanıcının kimliği zaten doğrudur; sorun, sunucunun isteğin kaynağını doğrulamamasıdır._
CSRF Nasıl Çalışır?
CSRF'in mantığını en iyi somut bir senaryo üzerinden anlamak mümkündür. Klasik ve öğretici bir örnek olan online bankacılık senaryosunu adım adım inceleyelim.
Senaryo: Online Bankacılık Üzerinden Para Transferi
Adım 1 — Kullanıcı online bankacılığa giriş yapar.
Kullanıcı, bank.example.com adresine girer, kullanıcı adı ve şifresiyle kimlik doğrulaması yapar. Sunucu, başarılı girişin ardından tarayıcıya bir session çerezi gönderir:
Set-Cookie: session=8f3a1c9d7e2b4f6a; HttpOnly; Path=/Set-Cookie: session=8f3a1c9d7e2b4f6a; HttpOnly; Path=/Bu noktadan itibaren tarayıcı, bank.example.com'a giden her istekte bu çerezi otomatik olarak ekleyecektir.
Adım 2 — Oturum canlı kalır.
Kullanıcı bankacılık işlemini bitirir ama sekmeyi kapatmaz, ya da "beni hatırla" seçeneği işaretliyse günler sonra bile oturum geçerliliğini korur. Birçok bankacılık uygulaması güvenlik amacıyla kısa oturum süreleri kullansa da, birçok web uygulaması (özellikle bankacılık dışı platformlar) oturumları saatlerce, hatta günlerce açık tutar.
Adım 3 — Kullanıcı kötü niyetli bir siteyi ziyaret eder.
Kullanıcı, farklı bir sekmede ya da farklı bir zamanda, saldırganın kontrolündeki attacker.example adresini ziyaret eder. Bu site tamamen zararsız görünen bir blog, bir yarışma sayfası ya da bir forum olabilir.
Adım 4 — Kötü niyetli sayfa otomatik olarak transfer isteği gönderir.
Sayfa yüklendiği anda, gizli bir form ya da bir <img> etiketi aracılığıyla, kurbanın tarayıcısı üzerinden bank.example.com'a bir para transferi isteği tetiklenir:
<!-- Yalnızca eğitim ve laboratuvar amaçlı örnektir -->
<form action="https://bank.example.com/transfer" method="POST" id="csrf-form">
<input type="hidden" name="to_account" value="ATTACKER-IBAN-0001">
<input type="hidden" name="amount" value="5000">
</form>
<script>
document.getElementById("csrf-form").submit();
</script><!-- Yalnızca eğitim ve laboratuvar amaçlı örnektir -->
<form action="https://bank.example.com/transfer" method="POST" id="csrf-form">
<input type="hidden" name="to_account" value="ATTACKER-IBAN-0001">
<input type="hidden" name="amount" value="5000">
</form>
<script>
document.getElementById("csrf-form").submit();
</script>Adım 5 — Sunucu isteği kabul eder çünkü çerez geçerlidir.
Tarayıcı bu isteği bank.example.com'a gönderirken, o domain'e ait session çerezini otomatik olarak ekler. Sunucu, gelen isteğin session çerezini kontrol eder, geçerli bir oturuma ait olduğunu görür ve isteği meşru kabul eder. Sunucu açısından bu istek, kullanıcının kendi bankacılık panelinden gönderdiği bir istekten hiçbir farklı görünmez.
Adım 6 — Para transferi gerçekleşir.
Sunucu, isteği işler ve parayı saldırganın hesabına transfer eder. Kullanıcı, bu işlemin gerçekleştiğinden bankaya giriş yapıp hesap özetini kontrol edene kadar habersizdir.
Bu Senaryonun Öğrettiği Temel Ders
Bu örnekte dikkat edilmesi gereken en kritik nokta şudur: sunucu tarafında hiçbir "hata" yoktur. Kullanıcı adı ve şifre doğru girilmiştir, session mekanizması doğru çalışmıştır, transfer endpoint'i beklendiği gibi işlev görmüştür. Sorun, sunucunun "bu isteği gerçekten kullanıcı mı, kullanıcının bilinçli eylemiyle mi gönderdi" sorusunu hiç sormamasıdır. CSRF, tam olarak bu sorunun sorulmamasının sonucudur.
CSRF Saldırı Akışı
CSRF saldırısının bileşenlerini ve aralarındaki ilişkiyi bir bütün olarak ele aldığımızda şu akış ortaya çıkar:
Kurban (Victim): Hedef sistemde oturumu açık olan, saldırının nihai mağduru olan kullanıcı.
Saldırgan (Attacker): Kötü niyetli isteği tasarlayan ve kurbanın bu isteği tetiklemesini sağlayacak ortamı hazırlayan kişi.
Kötü Niyetli Web Sitesi (Malicious Website): Saldırganın kontrolündeki, kurbanın ziyaret etmesi için sosyal mühendislik yöntemleriyle (e-posta, forum linki, reklam, kısaltılmış URL) yönlendirildiği sayfa. Bu sayfa, hedef siteye otomatik istek gönderen HTML/JavaScript kodunu barındırır.
Tarayıcı (Browser): Kurbanın kötü niyetli sayfayı açtığı ortam. Tarayıcı, kötü niyetli sayfadaki formun ya da script'in tetiklediği isteği, hedef sitenin domain'ine ait çerezlerle birlikte gönderir. Burada kritik nokta, tarayıcının bu isteğin "nereden" geldiğini değil, "nereye" gittiğini baz alarak çerez eklemesidir.
Hedef Web Sitesi (Target Website): İsteği alan, session çerezini doğrulayan ve isteği işleyen sunucu.
Session Çerezi (Session Cookie): Bu akışın can damarıdır. Çerezlerin domain bazlı otomatik gönderim davranışı olmasaydı, CSRF diye bir saldırı türü de var olmazdı. Tarayıcı, "bu istek attacker.example'dan tetiklendi ama hedefi bank.example.com, o hâlde bank.example.com'un çerezini ekleyeyim" mantığıyla çalışır. Çerez, isteğin kim tarafından "başlatıldığını" değil, isteğin "kime ait oturuma dahil olduğunu" gösterir; sunucu bu ikisini birbirine karıştırdığında CSRF ortaya çıkar.
Aşağıdaki akış özetlenebilir:
Kurban (oturum açık)
→ Kötü niyetli siteyi ziyaret eder
→ Kötü niyetli sayfa gizli form/istek tetikler
→ Tarayıcı isteği hedef siteye gönderir + session çerezini otomatik ekler
→ Hedef sunucu çerezi doğrular, isteği "meşru" sayar
→ İstenen işlem (transfer, şifre değişikliği vb.) gerçekleşirKurban (oturum açık)
→ Kötü niyetli siteyi ziyaret eder
→ Kötü niyetli sayfa gizli form/istek tetikler
→ Tarayıcı isteği hedef siteye gönderir + session çerezini otomatik ekler
→ Hedef sunucu çerezi doğrular, isteği "meşru" sayar
→ İstenen işlem (transfer, şifre değişikliği vb.) gerçekleşirCSRF Türleri
CSRF saldırıları, kullandıkları HTTP metoduna ve senaryonun karmaşıklığına göre farklı kategorilere ayrılır. Her birinin kendine has istismar teknikleri ve savunma zorlukları vardır.
GET Tabanlı CSRF
Uygulama, state değiştiren bir işlemi (örneğin hesap silme, e-posta güncelleme) yanlışlıkla GET metodu ile gerçekleştiriyorsa, saldırı son derece basitleşir. Çünkü bir <img> etiketi bile bu isteği tetiklemek için yeterlidir:
<!-- Sadece eğitim amaçlı, laboratuvar ortamına özgü örnek -->
<img src="https://vulnerable-app.example/account/delete?confirm=true" width="0" height="0"><!-- Sadece eğitim amaçlı, laboratuvar ortamına özgü örnek -->
<img src="https://vulnerable-app.example/account/delete?confirm=true" width="0" height="0">Kurban bu sayfayı ziyaret ettiği anda tarayıcı, görseli yüklemeye çalışırken bu URL'e otomatik olarak istek gönderir ve hesap silme işlemi tetiklenebilir. GET tabanlı CSRF'in tehlikeli olmasının nedeni, saldırganın herhangi bir kullanıcı etkileşimine ihtiyaç duymamasıdır; sayfa yüklendiği an saldırı da gerçekleşir.
Neden Önemli:_ HTTP spesifikasyonu, GET isteklerinin "idempotent" ve yan etkisiz olması gerektiğini öngörür. State değiştiren işlemler için GET kullanmak, sadece CSRF riskini artırmakla kalmaz; aynı zamanda arama motoru botlarının, tarayıcı önbelleğinin veya link önizleme sistemlerinin bu işlemleri kazara tetiklemesine de yol açabilir._
POST Tabanlı CSRF
Daha yaygın olan senaryo budur. Uygulama state değiştiren işlemleri doğru şekilde POST ile gerçekleştirir, ama isteğin kaynağını doğrulamaz. Saldırgan bu durumda kurbanın tarayıcısını, otomatik olarak submit edilen bir form aracılığıyla POST isteği göndermeye zorlar. Bir önceki bölümdeki bankacılık örneğindeki form, tam olarak bu türe girer.
POST tabanlı CSRF, GET tabanlısına göre biraz daha fazla hazırlık gerektirir (bir form ve genellikle bir JavaScript satırı), ama kurbanın herhangi bir işlem yapmasına, hatta fark etmesine bile gerek kalmadan otomatik olarak tetiklenebilir.
AJAX Tabanlı CSRF
Bazı uygulamalar, form submit yerine JavaScript'in fetch ya da XMLHttpRequest API'lerini kullanarak istek gönderir. Eğer hedef site CORS (Cross-Origin Resource Sharing) yapılandırmasını gevşek bırakmışsa ya da saldırgan sadece isteği tetiklemek isteyip cevabı okumaya ihtiyaç duymuyorsa, bu tür de mümkündür:
// Sadece eğitim amaçlı, laboratuvar ortamına özgü örnek
fetch("https://vulnerable-app.example/api/update-email", {
method: "POST",
credentials: "include",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ email: "attacker@example.com" })
});// Sadece eğitim amaçlı, laboratuvar ortamına özgü örnek
fetch("https://vulnerable-app.example/api/update-email", {
method: "POST",
credentials: "include",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ email: "attacker@example.com" })
});Burada credentials: "include" parametresi kritik önemdedir; bu, tarayıcının isteğe hedef domain'in çerezlerini eklemesini sağlar. Normal şartlarda Same-Origin Policy, saldırganın bu isteğin cevabını okumasını engeller, ama saldırganın amacı zaten cevabı okumak değil, sadece işlemi tetiklemektir; bu yüzden SOP burada koruma sağlamaz.
Login CSRF
Bu, daha az bilinen ama ilginç bir varyanttır. Saldırgan burada kurbanın hesabını değil, kendi hesabını hedef alır. Saldırgan, kurbanı kendi (saldırganın) kimlik bilgileriyle, kurbanın haberi olmadan hedef siteye "giriş yaptırır". Amaç, kurbanın daha sonra girdiği hassas verileri (örneğin bir arama sorgusu, bir ödeme bilgisi) saldırganın hesabında toplamaktır. Kurban, kendi hesabında olduğunu düşünerek işlem yapmaya devam eder, ama aslında saldırganın hesabı içindedir.
Multi-Step CSRF
Bazı işlemler tek bir istekle değil, birden fazla adımlı bir süreçle gerçekleşir (örneğin önce "işlem onayı iste", sonra "OTP doğrula" gibi). Eğer her adım tek başına CSRF korumasından yoksunsa, saldırgan bu adımları zincirleme şekilde otomatikleştirebilir. Örneğin, kurbanın tarayıcısında sırayla tetiklenen birden fazla gizli form veya setTimeout ile zamanlanmış istekler kullanılarak çok adımlı bir işlem, kurban fark etmeden tamamlanabilir. Bu tür, tek adımlı korumaların yeterli sanıldığı ama aslında akışın bütünsel güvenliğinin göz ardı edildiği durumlarda ortaya çıkar.
Gerçek Laboratuvar Ortamında Gösterim
Aşağıdaki bölüm, yalnızca yasal ve izole bir laboratuvar ortamı olan DVWA (Damn Vulnerable Web Application) üzerinde, eğitim amacıyla gerçekleştirilmiştir. Burada anlatılan teknikler hiçbir şekilde izinsiz sistemler üzerinde denenmemelidir; CSRF de dahil olmak üzere herhangi bir zafiyetin, sahibinden yazılı izin alınmadan üçüncü taraf sistemlerde test edilmesi yasadışıdır ve ciddi hukuki sonuçlar doğurabilir.
Ortam Hazırlığı
DVWA, güvenlik seviyesi ayarlanabilen, kasıtlı olarak zafiyetli bırakılmış bir PHP/MySQL uygulamasıdır. Güvenlik seviyesini "Low" olarak ayarladığımızda, CSRF koruması tamamen devre dışı bırakılmış olur; bu da zafiyetin temel mekanizmasını net biçimde gözlemlememizi sağlar.
Adım 1 — İsteğin Yakalanması (Capture Request)
DVWA'nın "CSRF" modülünde, kullanıcı şifresini değiştirme formu bulunur. Burp Suite proxy'si üzerinden bu formu doldurup gönderdiğimizde, Burp'ün Proxy > HTTP History sekmesinde şu isteği görürüz:
GET /vulnerabilities/csrf/?password_new=yenisifre123&password_conf=yenisifre123&Change=Change HTTP/1.1
Host: dvwa.local
Cookie: PHPSESSID=abc123def456; security=lowGET /vulnerabilities/csrf/?password_new=yenisifre123&password_conf=yenisifre123&Change=Change HTTP/1.1
Host: dvwa.local
Cookie: PHPSESSID=abc123def456; security=lowBurada dikkat çekici nokta, şifre değiştirme gibi kritik bir işlemin GET metodu ile ve herhangi bir CSRF token'ı olmadan gerçekleştirilmesidir. Bu, GET tabanlı CSRF türünün klasik bir örneğidir.
Adım 2 — PoC Oluşturma (Generate PoC)
Yakalanan isteği temel alarak, laboratuvar ortamında test amaçlı bir kanıt-konsept (Proof of Concept) sayfası hazırlıyoruz:
<!-- Yalnızca DVWA laboratuvar ortamında, eğitim amaçlı test edilmiştir -->
<html>
<body>
<h3>Kanıt Amaçlı Test Sayfası</h3>
<img src="http://dvwa.local/vulnerabilities/csrf/?password_new=hacked123&password_conf=hacked123&Change=Change" style="display:none">
</body>
</html><!-- Yalnızca DVWA laboratuvar ortamında, eğitim amaçlı test edilmiştir -->
<html>
<body>
<h3>Kanıt Amaçlı Test Sayfası</h3>
<img src="http://dvwa.local/vulnerabilities/csrf/?password_new=hacked123&password_conf=hacked123&Change=Change" style="display:none">
</body>
</html>Adım 3 — Saldırının Yürütülmesi (Execute Attack)
Bu HTML dosyasını, aynı tarayıcı oturumunda (yani DVWA'ya giriş yapmış durumdayken) yerel bir sunucu üzerinden açtığımızda, tarayıcı <img> etiketinin src değerini bir görsel isteği gibi işler ve bu URL'e otomatik olarak GET isteği gönderir.
Adım 4 — Sonucun Gözlemlenmesi (Observe Result)
DVWA hesabına tekrar giriş yapmaya çalıştığımızda, eski şifrenin artık geçerli olmadığını, hesabın şifresinin "hacked123" olarak değiştiğini görürüz. Bu, CSRF saldırısının başarıyla tamamlandığını gösterir.
Önemli Not:_ Bu gösterim yalnızca CSRF mekanizmasının nasıl çalıştığını somutlaştırmak amacıyla, izole ve kişisel bir laboratuvar ortamında yapılmıştır. DVWA, bWAPP, OWASP Juice Shop ve Mutillidae gibi platformlar, tam olarak bu tür eğitim amaçlı denemeler için tasarlanmıştır ve gerçek sistemlere hiçbir zaman izinsiz saldırı düzenlenmemelidir._
Burp Suite İş Akışı
Sızma testi uzmanları, CSRF zafiyetlerini tespit ve doğrulama sürecinde genellikle Burp Suite'i kullanır. Aşağıda, DVWA üzerinde izlenen adımlar özetlenmiştir.
1. İsteğin Yakalanması (Intercept Request)
Burp Suite'in Proxy modülü aktifken, tarayıcı üzerinden hedef işlemi (örneğin şifre değiştirme) gerçekleştiriyoruz. Burp, bu isteği yakalar ve Proxy History'de kaydeder. Bu aşamada isteğin hangi parametreleri taşıdığı, CSRF token'ı içerip içermediği ve hangi HTTP metodunun kullanıldığı incelenir.
2. CSRF PoC Oluşturma (Generate CSRF PoC)
Burp Suite, yakalanan bir isteğe sağ tıklandığında "Engagement tools > Generate CSRF PoC" seçeneğini sunar. Bu özellik, seçilen istek için otomatik olarak bir HTML formu ve gerekli JavaScript kodunu üretir. Üretilen PoC, isteğin tüm parametrelerini içeren gizli bir form ve bu formu otomatik submit eden bir script barındırır.
3. HTML'in Düzenlenmesi (Modify HTML)
Burp'ün otomatik oluşturduğu PoC genellikle olduğu gibi kullanılabilir, ama gerçekçi bir senaryo simülasyonu için genellikle biraz düzenleme yapılır: örneğin formun kullanıcıya görünmesini engellemek için style="display:none" eklenir, ya da form otomatik submit yerine bir buton tıklamasıyla (sosyal mühendislik senaryosunu simüle etmek için) tetiklenecek şekilde değiştirilir.
4. Kötü Niyetli Sayfanın Barındırılması (Host Malicious Page)
Laboratuvar ortamında, bu PoC dosyası basit bir HTTP sunucusu üzerinden (örneğin Python'ın http.server modülüyle) yerel ağda barındırılır:
python3 -m http.server 8000python3 -m http.server 8000Bu, gerçek dünyada saldırganın kendi domain'inde barındıracağı sayfanın laboratuvar ortamındaki karşılığıdır.
5. Yürütme (Execute)
Test kullanıcısı (yani biz), DVWA oturumu açıkken bu PoC sayfasını ziyaret eder. Tarayıcı, sayfadaki formu otomatik olarak submit eder ve istek DVWA sunucusuna, mevcut session çerezleriyle birlikte gönderilir.
6. Cevabın Gözlemlenmesi (Observe Response)
Burp'ün Proxy History'sinde, PoC sayfası üzerinden tetiklenen isteğin gerçekten DVWA sunucusuna ulaştığını ve sunucunun bu isteği kabul ettiğini doğrularız. Ardından hedef işlemin (şifre değişikliği) gerçekten gerçekleştiğini, uygulama arayüzünden veya veritabanı kaydından teyit ederiz.
Bu iş akışı, gerçek bir sızma testi raporunda CSRF bulgusunu kanıtlamak için standart bir yöntemdir; Burp Suite'in bu özelliği, manuel PoC yazma sürecini büyük ölçüde hızlandırır.
CSRF Nasıl Tespit Edilir?
CSRF zafiyetlerinin tespiti, hem manuel analiz hem de otomatik araçlarla desteklenmiş bir süreçtir.
Manuel Test
Manuel testte odaklanılması gereken temel sorular şunlardır:
- İşlem, state değiştiren bir istek mi (POST, PUT, DELETE ya da hatalı kullanılmış GET)?
- İstek içinde tahmin edilemez, sunucu tarafında doğrulanan bir CSRF token var mı?
- Token varsa, bu token her istekte değişiyor mu, yoksa sabit mi kalıyor?
- Token, session'dan bağımsız olarak tahmin edilebilir ya da tekrar kullanılabilir mi?
- İstek,
OriginveyaRefererheader'ları olmadan da kabul ediliyor mu? - Token doğrulaması sadece istemci tarafında mı yapılıyor (örneğin sadece JavaScript kontrolü), yoksa sunucu tarafında da mı?
Eksik CSRF Token'ı
En temel gösterge, state değiştiren bir isteğin hiçbir token içermemesidir. Bu durumda, sunucunun isteğin kaynağını doğrulayacak hiçbir mekanizması yok demektir.
Origin ve Referer Header'ları
Sunucu tarafında bazı uygulamalar, Origin veya Referer header'larını kontrol ederek isteğin gerçekten kendi domain'inden mi geldiğini doğrulamaya çalışır. Test sırasında bu header'lar kaldırıldığında ya da farklı bir değerle değiştirildiğinde isteğin hâlâ kabul edilip edilmediği kontrol edilmelidir. Eğer sunucu bu header'lar eksik olduğunda isteği reddetmiyorsa, bu kontrol yetersiz demektir.
Çerez Öznitelikleri
Session çerezinin SameSite özniteliği incelenmelidir. SameSite=None olarak ayarlanmış ve Secure bayrağı taşımayan çerezler, cross-site isteklerde otomatik olarak gönderilmeye devam eder ve CSRF riskini artırır. SameSite=Lax ya da SameSite=Strict olarak ayarlanmış çerezler ise CSRF riskini önemli ölçüde azaltır, ama tamamen ortadan kaldırmayabilir (bu konuya Koruma Yöntemleri bölümünde detaylı değineceğiz).
Otomatik Araçlar
Burp Suite: Proxy History üzerinden geçen tüm istekler manuel olarak incelenebilir; ayrıca Burp'ün pasif tarayıcısı (Burp Scanner, Pro sürümde) bazı CSRF göstergelerini otomatik olarak işaretleyebilir. "Generate CSRF PoC" özelliği, bulunan zafiyetin doğrulanmasında kullanılır.
OWASP ZAP: ZAP'in otomatik tarayıcısı, formlarda CSRF token'ı eksikliğini tespit edebilen kurallara sahiptir. "Anti-CSRF Tokens Scanner" adlı pasif tarama kuralı, formlarda token bulunup bulunmadığını kontrol eder ve eksik olduğu durumları raporlar.
Not:_ Otomatik araçlar CSRF token'ının varlığını tespit edebilir, ama token'ın kriptografik olarak güçlü, tahmin edilemez ve doğru şekilde doğrulanıp doğrulanmadığını her zaman garanti edemez. Bu yüzden manuel doğrulama, özellikle token'ın sunucu tarafında gerçekten kontrol edilip edilmediğini teyit etmek için vazgeçilmezdir._
Koruma Yöntemleri
CSRF'e karşı savunma, tek bir çözümden ziyade katmanlı bir yaklaşım gerektirir. Aşağıda, sektör standardı haline gelmiş yöntemler, çalışma mantıklarıyla birlikte açıklanmıştır.
CSRF Token (Synchronizer Token Pattern)
Bu, en yaygın ve en güvenilir kabul edilen yöntemdir. Mantığı şöyledir: sunucu, kullanıcıya bir form gösterirken, o oturuma özgü, tahmin edilemez ve kriptografik olarak rastgele üretilmiş bir token oluşturur. Bu token hem sunucu tarafında (session içinde) saklanır hem de forma gizli bir alan olarak eklenir.
<form action="/transfer" method="POST">
<input type="hidden" name="csrf_token" value="a3f9c2e1b8d47f0629de9c1a45f8b21c">
<!-- diğer form alanları -->
</form><form action="/transfer" method="POST">
<input type="hidden" name="csrf_token" value="a3f9c2e1b8d47f0629de9c1a45f8b21c">
<!-- diğer form alanları -->
</form>Kullanıcı formu submit ettiğinde, sunucu gelen token'ı session'da saklanan token ile karşılaştırır. Eşleşmiyorsa istek reddedilir. Bu yöntemin gücü şuradan gelir: saldırgan, kurbanın session'ına özgü bu token'ı önceden bilemez, çünkü token her session için ayrı üretilir ve saldırganın kendi sayfası bu token'ı hedef siteden okuyamaz (Same-Origin Policy bunu engeller).
Neden İşe Yarar: Saldırgan kör bir şekilde istek göndertebilir ama isteğin içine geçerli bir token koyamaz, çünkü token'ı bilmesi mümkün değildir.
Double Submit Cookie
Bu yöntemde, sunucu bir CSRF token'ı üretir ve bunu hem bir çerez olarak hem de yanıt gövdesinde (örneğin bir meta tag veya gizli form alanı olarak) kullanıcıya gönderir. İstemci taraflı JavaScript, çerezden okuduğu token'ı, isteğin bir header'ına (örneğin X-CSRF-Token) ekler. Sunucu, gelen istekte hem çerezdeki token'ı hem de header'daki token'ı karşılaştırır; ikisi eşleşmiyorsa istek reddedilir.
// İstemci tarafı örnek kullanım
const csrfToken = getCookie("csrf_token");
fetch("/api/update-profile", {
method: "POST",
headers: { "X-CSRF-Token": csrfToken },
credentials: "include",
body: JSON.stringify({ name: "yeni isim" })
});// İstemci tarafı örnek kullanım
const csrfToken = getCookie("csrf_token");
fetch("/api/update-profile", {
method: "POST",
headers: { "X-CSRF-Token": csrfToken },
credentials: "include",
body: JSON.stringify({ name: "yeni isim" })
});Neden İşe Yarar: Saldırgan, kurbanın tarayıcısını isteği göndermeye zorlayabilir, ama Same-Origin Policy nedeniyle kurbanın çerezindeki token değerini kendi sayfasından JavaScript ile okuyamaz. Bu yüzden header'a doğru token'ı ekleyemez.
Bu yöntemin sunucu tarafında session state tutmaya ihtiyaç duymaması, özellikle stateless API mimarilerinde tercih edilmesinin nedenidir. Ancak dikkatli uygulanmazsa (örneğin token'ın HttpOnly olmayan bir çerezde tutulması gerektiği unutulursa ya da subdomain'ler arası çerez paylaşımı riskleri göz ardı edilirse) zayıflayabilir.
SameSite Çerez Özniteliği
SameSite, tarayıcı seviyesinde uygulanan, RFC 6265bis ile standartlaştırılmış bir çerez özniteliğidir. Üç değer alabilir:
- Strict: Çerez, yalnızca isteğin kaynağı da hedef site ile aynı ise gönderilir. Cross-site hiçbir istekte (link tıklaması dahil) çerez gönderilmez. En güvenli ama kullanıcı deneyimini etkileyebilecek seçenektir.
- Lax: Çerez, cross-site GET isteklerinde (örneğin bir linke tıklanarak siteye gidilmesi gibi üst düzey navigasyonlarda) gönderilir, ama cross-site POST, form submit gibi isteklerde gönderilmez. Modern tarayıcılarda varsayılan değer budur.
- None: Çerez her koşulda gönderilir; bu değer kullanıldığında
Securebayrağının da zorunlu olarak eklenmesi gerekir.
Set-Cookie: session=8f3a1c9d; SameSite=Lax; Secure; HttpOnlySet-Cookie: session=8f3a1c9d; SameSite=Lax; Secure; HttpOnlyNeden İşe Yarar: SameSite=Lax veya Strict, tarayıcının kendisi seviyesinde cross-site isteklerde çerezin gönderilmesini engeller. Bu, sunucu tarafında hiçbir ek kod yazılmasa bile önemli bir koruma katmanı sağlar. Ancak bu korumanın da sınırları vardır: GET tabanlı state-changing endpoint'ler, Lax modunda yine de risk altında kalabilir, çünkü üst düzey navigasyon (bir linke tıklama) GET isteklerinde çerez hâlâ gönderilir.
Önemli Not:_ SameSite, CSRF token'larının yerini almaz; onu tamamlayan bir savunma katmanıdır. Defense in depth prensibi gereği, ikisinin birlikte kullanılması önerilir. Ayrıca eski tarayıcı sürümleri SameSite'i desteklemeyebilir, bu da tek başına bu korumaya güvenmenin riskli olduğunu gösterir._
Origin Doğrulama
Sunucu, gelen isteğin Origin header'ını kontrol ederek isteğin beklenen domain'den gelip gelmediğini doğrulayabilir. Origin header'ı, tarayıcı tarafından otomatik eklenir ve JavaScript ile manipüle edilemez, bu da onu güvenilir bir kaynak yapar.
Origin: https://bank.example.comOrigin: https://bank.example.comSunucu, bu değeri kendi beklediği domain listesiyle karşılaştırır. Eşleşmiyorsa istek reddedilir. Bu yöntem özellikle POST isteklerinde etkilidir çünkü modern tarayıcılar, cross-origin POST isteklerinde Origin header'ını neredeyse her zaman ekler.
Referer Doğrulama
Referer header'ı, isteğin hangi sayfadan tetiklendiğini gösterir ve benzer bir doğrulama mantığıyla kullanılabilir. Ancak Origin'e göre daha az güvenilirdir, çünkü bazı tarayıcı yapılandırmaları, gizlilik eklentileri veya proxy'ler Referer header'ını kaldırabilir veya boş bırakabilir. Sunucunun yalnızca Referer'a dayanarak karar vermesi, header eksik olduğunda isteğin nasıl ele alınacağı konusunda belirsizlik yaratır; bu nedenle Referer, tek başına değil Origin ile birlikte, tamamlayıcı bir kontrol olarak kullanılmalıdır.
Yeniden Kimlik Doğrulama (Re-authentication)
Özellikle hassas işlemler için (şifre değiştirme, hesap silme, ödeme yöntemi ekleme gibi) kullanıcıdan mevcut şifresini veya bir OTP kodunu tekrar girmesi istenebilir. Bu yöntem, CSRF token'ı bypass edilmiş olsa bile saldırganın kurbanın şifresini bilmediği için işlemi tamamlayamamasını sağlar.
Neden İşe Yarar: Saldırgan kör bir şekilde istek göndertebilir, ama kurbanın şifresini veya OTP kodunu bilmesi mümkün değildir; bu yüzden re-authentication adımı zincirin kırılmasına neden olur.
CAPTCHA
CAPTCHA, özellikle otomatikleştirilmiş isteklere karşı bir engel oluşturur. Ancak CSRF bağlamında CAPTCHA'nın avantajları kadar önemli sınırlamaları da vardır.
Avantajları: Otomatik form submit senaryolarında, kurbanın kendisinin manuel olarak CAPTCHA'yı çözmesi gerektiğinden, saldırganın isteği görünmez şekilde tetiklemesi zorlaşır.
Sınırlamaları: CAPTCHA, kullanıcı deneyimini olumsuz etkiler ve her işlem için uygulanması pratik değildir. Ayrıca CAPTCHA çözümünün kendisi bazı senaryolarda otomatikleştirilebilir (özellikle zayıf CAPTCHA implementasyonlarında) veya sosyal mühendislikle kurbana çözdürülebilir (örneğin kurbanı "bu CAPTCHA'yı çöz" diye kandıran bir sayfa üzerinden). Bu nedenle CAPTCHA, CSRF token'ı gibi temel bir korumanın yerine değil, ek bir sürtünme katmanı olarak düşünülmelidir.
Geliştiricilerin Sık Yaptığı Hatalar
CSRF zafiyetlerinin gerçek dünyada hâlâ sıkça karşımıza çıkmasının arkasında, tekrar eden birkaç geliştirici hatası yatar.
CSRF Token'ı Bulunmaması: En temel ve en yaygın hata. Özellikle özel olarak yazılmış (framework'ün varsayılan korumasını kullanmayan) form işleme kodlarında bu eksiklik sıkça görülür.
State Değiştiren İşlemler İçin GET Kullanımı: Hesap silme, şifre sıfırlama, e-posta değiştirme gibi işlemlerin GET metodu ile yapılması, saldırının karmaşıklığını neredeyse sıfıra indirir. HTTP metod semantiğine uyulmaması, CSRF riskini doğrudan artırır.
Token'ın Tekrar Kullanılması: Bazı uygulamalar, CSRF token'ını kullanıcı oturumu boyunca hiç değiştirmez ya da token'ı birden fazla işlemde tekrar tekrar kullanır. Eğer bu token bir şekilde sızarsa (örneğin bir XSS zafiyeti, loglama hatası veya Referer header sızıntısı yoluyla), saldırgan bu token'ı defalarca kullanabilir.
Tahmin Edilebilir Token'lar: Token üretiminde zayıf rastgelelik kaynakları kullanılması (örneğin timestamp bazlı ya da sıralı token'lar), saldırganın token'ı tahmin etmesine olanak tanır. CSRF token'ları, kriptografik olarak güvenli rastgele sayı üreteçleri (CSPRNG) ile oluşturulmalıdır.
SameSite'ı Devre Dışı Bırakma: Bazı geliştiriciler, cross-domain entegrasyon ihtiyaçları (örneğin bir iframe içinde çalışan üçüncü taraf widget) nedeniyle çerezleri SameSite=None olarak ayarlar. Bu, gerekli olmayan durumlarda yapıldığında, tarayıcının sağladığı önemli bir savunma katmanının kaybedilmesine neden olur.
Yalnızca Referer'a Güvenme: Daha önce belirtildiği gibi, Referer header'ı bazı durumlarda tarayıcı veya ağ yapılandırması nedeniyle gönderilmeyebilir. Sunucunun bu header'a tek başına güvenmesi ve eksik olduğunda isteği reddetmek yerine kabul etmesi, korumanın etkisiz kalmasına yol açar.
Gerçek Dünya Örnekleri
CSRF, akademik bir kavram olmanın ötesinde, gerçek dünyada büyük platformları etkilemiş bir zafiyet sınıfıdır. Aşağıdaki örnekler, teknik doğruluğu korunarak ve abartıya kaçmadan özetlenmiştir.
Geçmiş yıllarda, popüler yönlendirici (router) yönetim panellerinde CSRF zafiyetleri sıkça raporlanmıştır; saldırganlar, kurbanın router yönetim paneline giriş yapmış olmasından faydalanarak DNS ayarlarını değiştiren isteklerini kurbanın tarayıcısı üzerinden tetiklemiştir. Bu tür saldırılar, kurbanın tüm internet trafiğinin saldırganın kontrolündeki DNS sunucularına yönlendirilmesine imkân tanımıştır.
Sosyal medya platformlarında da geçmişte CSRF zafiyetleri bulunmuş; bug bounty programları kapsamında araştırmacılar, kullanıcı ayarlarını (e-posta adresi, gizlilik tercihleri gibi) değiştiren endpoint'lerin CSRF korumasından yoksun olduğunu raporlamıştır. Bu bulgular, ilgili platformlar tarafından hızla yamanmıştır.
İçerik yönetim sistemleri (CMS) ekosisteminde de CSRF, eklenti ve tema geliştiricilerinin sıkça atladığı bir konu olmuştur; özellikle yönetici paneli işlemlerinde CSRF token'ı eksikliği, saldırganların bir yöneticiyi kötü niyetli bir sayfaya yönlendirerek yönetici yetkisiyle işlem yaptırmasına imkân tanıyan senaryolara zemin hazırlamıştır.
Bu örneklerin ortak noktası şudur: CSRF, genellikle "yardımcı" veya "ikincil" görülen işlevlerde (ayarlar sayfaları, yönetim panelleri, entegrasyon endpoint'leri) gözden kaçırılır. Ana kimlik doğrulama akışı güvenli olsa bile, bu tür ikincil işlevlerin CSRF korumasından yoksun bırakılması, saldırganlara giriş noktası sağlar.
Özet
CSRF, teknik olarak karmaşık bir istismar gerektirmeyen, buna rağmen etkisi ciddi olabilen bir zafiyet sınıfıdır. Bu makalede ele aldığımız temel noktaları bir araya getirdiğimizde şu sonuçlara varıyoruz:
CSRF, bir yazılım hatasından değil, sistemler arası güven ilişkisinin kötüye kullanılmasından doğar. Sunucu, geçerli bir session çerezi taşıyan her isteğin kullanıcının bilinçli eylemi olduğunu varsayar; bu varsayım, CSRF saldırısının temelini oluşturur.
Saldırının başarılı olması için kurbanın hedef sitede oturumunun açık olması ve kötü niyetli bir sayfayı ziyaret etmesi yeterlidir; kurbanın herhangi bir ek işlem yapması genellikle gerekmez.
Etkili savunma, tek bir yönteme değil katmanlı bir yaklaşıma dayanır: CSRF token'ları (Synchronizer Token Pattern veya Double Submit Cookie), SameSite çerez özniteliği, Origin/Referer doğrulaması ve hassas işlemler için re-authentication, bir arada kullanıldığında güçlü bir savunma hattı oluşturur.
Geliştiricilerin en sık yaptığı hatalar, genellikle temel HTTP semantiğine uyulmaması (state değiştiren işlemler için GET kullanımı) ve token mekanizmalarının doğru yapılandırılmamasıdır.
En önemli ders şudur: CSRF, kullanıcının güvenini değil, sistemin kullanıcıya duyduğu güveni istismar eder. Kullanıcı hiçbir hata yapmaz; şifresini kimseyle paylaşmaz, şüpheli bir linke tıklamaz gibi görünebilir. Saldırı, tamamen kullanıcının bilgisi ve rızası dışında, tarayıcının teknik davranışları üzerinden gerçekleşir. Bu nedenle CSRF'e karşı savunma, kullanıcı farkındalığından çok, uygulama mimarisinin ve HTTP protokolünün doğru kullanılmasına bağlıdır.
Web Güvenliği Serisi
✅ Bölüm 1 — Cross-Site Scripting (XSS)
✅ Bölüm 2 — SQL Injection
✅ Bölüm 3 — Cross-Site Request Forgery (Bu Yazı)
⏳ Bölüm 4 — Server-Side Request Forgery (SSRF)
Kaynaklar
- OWASP Foundation, Cross-Site Request Forgery Prevention Cheat Sheet
- OWASP Cheat Sheet Series, resmi GitHub deposu
- PortSwigger Web Security Academy, CSRF bölümü
- MDN Web Docs, SameSite cookies dokümantasyonu
- MITRE, CWE-352: Cross-Site Request Forgery (CSRF)
- RFC 6265bis, Cookies: HTTP State Management Mechanism, SameSite özniteliği tanımı