Content Security Policy (CSP) 2026: XSS Savunma ve Pratik Uygulama

CSP header nedir sorusunun kısa cevabı: Content-Security-Policy, tarayıcıya hangi kaynaktan script, stil, görsel, font ve XHR/fetch yüklenebileceğini bildiren bir HTTP yanıt başlığıdır. 2025 itibarıyla XSS (Cross-Site Scripting) hâlâ OWASP Top 10’da en sık raporlanan ilk üç zafiyet arasında yer alıyor ve HackerOne’ın 2024 raporuna göre platform üzerinde ödüllendirilen tüm zafiyetlerin yaklaşık %20’sini XSS varyantları oluşturuyor. CSP, doğru yapılandırıldığında inline script çalıştırılmasını engelleyerek bu saldırı yüzeyinin büyük kısmını fiilen kapatır. Strict-dynamic + nonce kombinasyonu kullanan bir CSP, klasik reflected/stored XSS payload’larının %95’inden fazlasını tarayıcı seviyesinde reddeder.

Bu yazı; CSP’nin 2026’da neden hâlâ savunma derinliğinin omurgası olduğunu, hangi direktif kombinasyonunun gerçekten koruma sağladığını, hangi yapılandırmaların yalancı güvenlik hissi verdiğini ve report-only modundan production enforce moduna geçişin nasıl kademeli yapılacağını anlatıyor. Senin için hedef: 30 dakika içinde sitenin CSP politikasını yazıp test edebileceğin bir oyun planı.

CSP Nedir, Tarayıcıda Nasıl Çalışır

Content-Security-Policy bir policy enforcement mekanizmasıdır. Sunucu, HTTP yanıtının başlığına bir politika yerleştirir; tarayıcı bu politikayı parse eder ve sayfa içindeki her kaynak isteğini (script, img, frame, fetch, font, stylesheet, manifest) bu kurallara karşı denetler. Politikaya uymayan kaynak yüklenmez; istenirse bir report-uri veya report-to uç noktasına JSON raporu gönderilir.

CSP, sunucu tarafında çalışan bir WAF değildir; istemci tarafı bir savunma katmanıdır. Saldırgan kötü amaçlı script’i HTML’e enjekte etmeyi başarsa bile tarayıcı, politikada izin verilmeyen kaynaktan script yüklemeyi veya inline script çalıştırmayı reddeder. Bu nedenle OWASP Top 10 savunmasında girdiyi temizleme (sanitization) ve çıktıyı kodlama (output encoding) ile birlikte üçüncü katman olarak konumlandırılır.

CSP iki taşıma yöntemiyle uygulanır: HTTP Content-Security-Policy başlığı veya HTML içindeki etiketi. HTTP başlığı daha güçlüdür çünkü frame-ancestors, report-uri, sandbox gibi direktifler meta etiketle çalışmaz. MDN’in CSP referansı hangi direktifin hangi taşıyıcıyla geçerli olduğunu listeler.

XSS saldırı türleri reflected stored DOM-based karşılaştırma soyut görseli
XSS saldırı türleri reflected stored DOM-based karşılaştırma soyut görseli

XSS Tehdit Manzarası ve CSP’nin Yeri

XSS üç ana türde gelir: reflected (URL parametresi üzerinden anlık), stored (veritabanına yazılıp her ziyarette çalışan), DOM-based (sunucuya hiç uğramadan tarayıcıda JavaScript ile tetiklenen). 2024 OWASP raporlarında DOM-based XSS oranı modern SPA mimarilerinin yaygınlaşmasıyla %35’lere ulaştı. Geleneksel WAF’lar DOM-based saldırıları büyük oranda kaçırır çünkü payload sunucudan geçmez.

CSP burada devreye girer. script-src 'self' 'nonce-{rastgele}' tanımlı bir politikada saldırgan HTML’e enjekte etse bile bu script’in geçerli bir nonce’u olmadığı için tarayıcı çalıştırmaz. Google’ın 2024 mühendislik blogunda paylaştığı verilere göre Gmail, YouTube ve Google Search’ün strict CSP’ye geçişi sonrası bu yüzeylerdeki XSS rapor sayısı yaklaşık %85 düştü.

Ancak CSP “yazıp unutulacak” bir başlık değildir. Yanlış yapılandırılan bir politika—örneğin script-src * 'unsafe-inline' 'unsafe-eval'—hiç CSP olmamasından farksızdır ve tarayıcı sekmesinde yeşil tik gösteren bir “güvenlik tiyatrosu” yaratır.

XSS TürüSaldırı VektörüCSP EtkinliğiEk Savunma
ReflectedURL query/path paramYüksek (nonce + strict-dynamic)Output encoding
StoredDB’den render edilen HTMLYüksek (script-src ‘self’ yetersiz, nonce şart)HTML sanitization (DOMPurify)
DOM-basedİstemci JS innerHTML/evalOrta (Trusted Types ile yüksek)Trusted Types API
Mutation XSSTarayıcı parser farklarıYüksek (inline yasaklı)Modern sanitizer kütüphaneleri
Self XSSSosyal mühendislikle konsola yapıştırmaDüşük (CSP konsolu engellemez)Kullanıcı uyarısı, DevTools warning

CSP Direktiflerinin Tam Anatomisi

CSP politikası noktalı virgülle ayrılmış direktif listesidir. Her direktif bir kaynak tipi için izinli kaynakları belirtir. W3C CSP Level 3 spesifikasyonu direktiflerin tamamını ve hangi keyword’ün hangi davranışı tetiklediğini tanımlar.

  • default-src: Diğer direktifler tanımlı değilse fallback. Genellikle 'self' ile başlanır.
  • script-src: JavaScript kaynakları. CSP’nin XSS savunmasının kalbi.
  • style-src: CSS kaynakları. Inline style attribute saldırı yüzeyi düşük ama mevcuttur.
  • img-src: Görsel kaynakları. Tracking pixel ve veri sızıntısı vektörleri için önemli.
  • connect-src: fetch, XHR, WebSocket, EventSource hedefleri.
  • frame-ancestors: Sayfanın hangi origin’lere iframe edilebileceği. X-Frame-Options’ın modern halefi.
  • form-action: Form gönderimlerinin hangi origin’e gidebileceği. Phishing redirect savunması.
  • base-uri: etiketiyle göreceli URL manipülasyonunu engeller; 'none' öneririm.
  • object-src: Flash/Java applet dönemi kalıntısı; her zaman 'none' olmalı.
  • upgrade-insecure-requests: HTTP kaynakları otomatik HTTPS’e yükseltir; karışık içerik temizliği.

Modern strict CSP için anahtar keyword’ler şunlardır:

  1. ‘self’: Yalnız aynı origin’den kaynak yükle.
  2. ‘nonce-{base64}’: Her istek için sunucu tarafında üretilen rastgele token. Yalnız bu nonce ile işaretli inline script çalışır.
  3. ‘sha256-{hash}’: Belirli bir inline bloğun hash’i. Sabit script’ler için kullanışlı.
  4. ‘strict-dynamic’: Nonce ile güvenilir bir script’in dinamik olarak yüklediği alt-script’lere de güven. Modern SPA’lar için kritik.
  5. ‘unsafe-inline’: İnline script/style izinli. Strict politikada YASAK; ancak nonce/hash varsa geri uyumluluk için yok sayılır.
  6. ‘unsafe-eval’: eval(), Function(), setTimeout(string) izinli. Kaçınılmalı.

Strict CSP: 2026’nın Önerilen Profili

Google’ın web.dev strict CSP rehberi Chrome ekibinin de imzasını taşıyan, geniş ekosistemde benimsenmiş referans şablondur. Şablonun özü: kaynak whitelist’i (allowlist) yerine nonce-based bir güven modeli kurmak. Çünkü 2016 Google araştırması (Weichselbaum ve diğ., “CSP Is Dead, Long Live CSP!”) taranan 1.6 milyon CSP politikasının %95’inin host whitelist’i nedeniyle bypass edilebildiğini gösterdi.

Önerilen strict CSP şablonu:

DirektifDeğerAmaç
default-src‘self’Tanımsız kaynaklar için güvenli fallback
script-src‘nonce-{rnd}’ ‘strict-dynamic’ https: ‘unsafe-inline’Modern + geri uyumlu güven zinciri
object-src‘none’Flash/Java applet vektörü kapalı
base-uri‘none’ injection bloklu
frame-ancestors‘none’ veya ‘self’Clickjacking koruması
form-action‘self’Form hijacking koruması
require-trusted-types-for‘script’DOM XSS API güvencesi
report-tocsp-endpointİhlal telemetrisi

Bu şablonda iki ince ayrıntı vardır. Birincisi https: ve 'unsafe-inline' CSP3 destekli tarayıcılarda görmezden gelinir; sadece CSP1/CSP2 destekleyen eski tarayıcılar için geri uyumluluk amaçlıdır. İkincisi 'strict-dynamic' sayesinde nonce’lu güvenilir bir loader script’in document.createElement('script') ile yüklediği script’lere de aynı güven yansır—webpack, Vite, Next.js gibi modern bundler’ların çalışması için bu kritiktir.

Nonce, Hash ve Strict-Dynamic Pratik Kullanımı

Nonce her HTTP yanıtında YENİDEN üretilmelidir. Aynı nonce’u tekrar kullanmak veya sayfada öngörülebilir bir değer (UUID dışı bir patern) yerleştirmek tüm savunmayı çürütür. Minimum 128 bit entropi (16 random byte → base64) standardıdır.

Express.js’te basit bir nonce middleware:

  • Üretim: crypto.randomBytes(16).toString('base64') ile her istekte yeni nonce.
  • Header injection: res.setHeader('Content-Security-Policy', "script-src 'nonce-" + nonce + "' 'strict-dynamic'").
  • Template paslaması: Nonce’u render context’ine geç, EJS/Handlebars/Pug ile
OmerOnal

Yorum (1)

  1. Ömer ÖNAL
    Mayıs 16, 2026

    Kurumsal güvenlik denetimlerinde sıkça karşılaştığım bir gerçek: zayıflıkların %60’ından fazlası bilinen ama yamanmamış component’lerden geliyor. Bu konuda denetim süreçlerinizi nasıl yönetiyorsunuz? Yorumlara yazabilirsiniz.

Yorum Yap

E-posta adresiniz yayınlanmayacak. Gerekli alanlar * ile işaretlenmişlerdir