24.01.2026

CSP Nedir? 30 Dakikada XSS’e Kalkan Kurun

CSP (Content Security Policy) ile XSS riskini azaltın. Nonce, hash ve report-only ile adım adım güvenli politika oluşturun.

CSP Nedir? 30 Dakikada XSS’e Kalkan Kurun

Meta Description

CSP nedir ve nasıl uygulanır? XSS saldırılarını azaltmak için nonce/hash, report-only ve güvenli header ayarlarını 30 dakikada öğrenin.

Giriş (Introduction)

CSP (Content Security Policy), modern web uygulamalarında XSS (Cross-Site Scripting) riskini ciddi şekilde azaltan en etkili savunma katmanlarından biridir. “Kodum temiz, XSS olmaz” demek çoğu zaman yetmez; üçüncü parti script’ler, yanlış yapılandırılmış inline kodlar, hatalı HTML render süreçleri bir gün mutlaka kapınızı çalar.

Bu yazıda CSP’yi sadece “teoride” anlatmayacağız: Hangi header’ı nasıl yazarsınız, nonce/hash ne işe yarar, report-only ile nasıl güvenle geçiş yaparsınız adım adım göreceksiniz. 30 dakika sonunda uygulamanızın güvenlik duruşu belirgin şekilde iyileşir.


CSP Nedir? (Content Security Policy)

CSP, tarayıcıya “Bu sayfada hangi kaynaklar (script, style, img, font, iframe vb.) nereden yüklenebilir?” diye kural seti veren bir güvenlik politikasıdır.

CSP sayesinde:

  • Beklenmedik bir script enjekte edilse bile tarayıcı çalıştırmayı reddedebilir.
  • Sadece izin verdiğiniz domain’lerden kaynak çekilir.
  • İhlaller raporlanarak görünür hale gelir.

Bunu neden yapmalıyım? Çünkü XSS’in maliyeti sadece “bir açık” değildir: kullanıcı oturum çalma, ödeme akışlarını manipüle etme, admin panel ele geçirme gibi sonuçlara gider. CSP, hatayı tamamen yok etmese de etkisini dramatik biçimde düşürür.


CSP’nin Temel Direktifleri (Kısa Harita)

Aşağıdaki tablo, günlük hayatta en çok kullanılan CSP direktiflerini özetler:

Direktif Ne kontrol eder? Sık kullanım
default-src Varsayılan kaynak politikası “Hiçbir şey izinli olmasın” yaklaşımı
script-src JS kaynakları XSS’e karşı ana direktif
style-src CSS kaynakları Inline style’ı yönetmek
img-src Görseller CDN, data URL ihtiyacı
connect-src XHR/fetch/WebSocket API domain’leri
font-src Font kaynakları Google Fonts / self-hosted
frame-src iframe kaynakları Ödeme sağlayıcı iframe’leri
base-uri <base> etiketini sınırlar URL manipülasyonunu azaltır
object-src Flash vb. Genelde none

LSI (ilişkili) terimler: XSS koruması, security header, nonce, hash, report-only, CORS, clickjacking, güvenlik politikası.


1) Hızlı Başlangıç: Minimum “Güvenli” CSP

İlk hedef: varsayılanı kapat, sadece gerekeni aç.

Örnek temel politika:

Content-Security-Policy: default-src 'self'; object-src 'none'; base-uri 'self'; frame-ancestors 'none'

Açıklama:

  • default-src 'self': Sadece kendi origin’inizden kaynak.
  • object-src 'none': Eski/tehlikeli embed’leri kapatır.
  • base-uri 'self': <base> ile yönlendirme/manipülasyonu kısıtlar.
  • frame-ancestors 'none': Sitenizin iframe içinde açılmasını engeller (clickjacking’e karşı).

Gerçek hayat örneği: Admin paneliniz bir başka sitede iframe içinde açılırsa, kullanıcı tıklamalarını başka yerlere yönlendiren clickjacking senaryoları doğabilir. frame-ancestors bunu keser.


2) En Kritik Kısım: script-src ve Inline Script Sorunu

Çoğu projede problem şudur: HTML içinde inline script vardır (örn. analytics init, config objesi, küçük snippet’ler). CSP ile bunu “serbest bırakırsanız” ('unsafe-inline') XSS savunmasını zayıflatırsınız.

Seçenek A: Nonce ile güvenli inline script

Her request’te rastgele bir nonce üretir, sadece o nonce’a sahip script’lerin çalışmasına izin verirsiniz.

CSP header:

Content-Security-Policy: default-src 'self'; script-src 'self' 'nonce-<RANDOM>'; object-src 'none'; base-uri 'self'

HTML:

<script nonce="<RANDOM>">
  window.__APP_CONFIG__ = { env: "prod" };
</script>

Seçenek B: Hash ile belirli inline script’e izin

Inline script içeriği değişmiyorsa hash kullanabilirsiniz.

Content-Security-Policy: script-src 'self' 'sha256-Base64EncodedHash...'

Bunu neden yapmalıyım? Çünkü unsafe-inline kullanmak, “sayfaya sızan her inline script çalışabilir” anlamına gelir. Nonce/hash, inline ihtiyacını güvenli hale getirir.


3) Report-Only ile Kırmadan Geçiş (Önerilen Yol)

CSP’yi bir anda “en sıkı” hale getirirseniz production’da bazı sayfalarınız bozulabilir (özellikle üçüncü parti script’ler, CDN’ler, fontlar, ödeme sayfaları).

Bu yüzden önce:

Content-Security-Policy-Report-Only: default-src 'self'; script-src 'self'; report-to csp-endpoint

Raporlamayı nasıl okurum?

  • Browser console’da CSP violation uyarıları görünür.
  • Gerçek kullanıcı trafiğinden gelen ihlalleri toplayıp izin listesini doğru kurarsınız.

Pratik: 3–7 gün report-only çalıştırın, log’ları inceleyin, ardından gerçek Content-Security-Policy header’ına geçin.


4) Node.js (Express) ile CSP Header’ı Eklemek

Aşağıdaki örnek, nonce üreterek her response’a CSP ekler.

import crypto from "crypto";
import express from "express";

const app = express();

app.use((req, res, next) => {
  const nonce = crypto.randomBytes(16).toString("base64");
  res.locals.nonce = nonce;

  res.setHeader(
    "Content-Security-Policy",
    [
      "default-src 'self'",
      `script-src 'self' 'nonce-${nonce}'`,
      "style-src 'self'",
      "img-src 'self' data:",
      "connect-src 'self' https://api.example.com",
      "object-src 'none'",
      "base-uri 'self'",
      "frame-ancestors 'none'"
    ].join("; ")
  );

  next();
});

app.get("/", (req, res) => {
  // Template motorunuzda nonce'u script tag'ine basın
  res.send(`
    <html>
      <head></head>
      <body>
        <script nonce="${res.locals.nonce}">
          console.log('CSP nonce ile çalıştı');
        </script>
      </body>
    </html>
  `);
});

app.listen(3000);

Yaygın hata

  • Nonce’ı ürettiniz ama HTML’de script tag’ine basmadınız → script’ler çalışmaz.

5) CDN, Analytics ve Üçüncü Parti Script’ler: Nasıl İzin Verilir?

Gerçek hayatta çoğu ekip şu ikilemde kalır: “Güvenlik mi, pazarlama araçları mı?”

Örnek bir senaryo:

  • Uygulama: self
  • Analytics: https://www.googletagmanager.com
  • Font: https://fonts.gstatic.com

Örnek politika (temkinli):

Content-Security-Policy:
  default-src 'self';
  script-src 'self' 'nonce-<RANDOM>' https://www.googletagmanager.com;
  connect-src 'self' https://analytics.google.com;
  style-src 'self' https://fonts.googleapis.com;
  font-src 'self' https://fonts.gstatic.com;
  img-src 'self' data: https://www.google-analytics.com;
  object-src 'none';
  base-uri 'self';
  frame-ancestors 'none'

İpucu:

  • Gereksiz wildcard kullanmayın: https://*.example.com bazen kaçınılmazdır ama önce net domain’lerle başlayın.
  • connect-src genelde unutulur; API çağrıları ve telemetry burada patlar.

6) CSP Checklist: Production’a Çıkmadan Önce

Aşağıdaki liste, “bozmadan sıkılaştırma” için pratik bir yol haritası:

  1. Report-Only ile başlayın (Content-Security-Policy-Report-Only).
  2. Console ve log’lardan ihlalleri toplayın.
  3. default-src 'self' + object-src 'none' + base-uri 'self' tabanını kurun.
  4. script-src için nonce (tercihen) kullanın.
  5. frame-ancestors ile clickjacking’i kapatın.
  6. CDN/3rd party domain’lerini minimum seviyede izinleyin.
  7. Policy’yi kademeli sıkılaştırın (ör. img-src data: gerçekten gerekli mi?).

Sık Sorulan Sorular (FAQ)

1) CSP XSS’i tamamen engeller mi?

Hayır. CSP, XSS’in etkisini azaltır ve birçok saldırıyı tarayıcı seviyesinde durdurur; yine de input validation ve output encoding şarttır.

2) unsafe-inline kullanmak zorunda mıyım?

Çoğu durumda hayır. Inline script ihtiyacını nonce veya hash ile çözebilirsiniz. unsafe-inline en son çare olmalı.

3) CSP ekledim, site bozuldu. Ne yapmalıyım?

Önce Content-Security-Policy-Report-Only ile ilerleyin. İhlal mesajlarına göre eksik domain/direktifleri ekleyin.

4) CSP ile CORS aynı şey mi?

Değil. CORS, tarayıcının cross-origin istekleri nasıl yöneteceğini belirler. CSP ise sayfanın hangi kaynakları yükleyip çalıştırabileceğini kısıtlar.


Sonuç

CSP, özellikle XSS’e karşı “tek başına mucize” olmasa da web uygulamalarında en hızlı değer üreten güvenlik katmanlarından biridir. Nonce/hash yaklaşımıyla inline script’leri kontrol altına alır, default-src ve script-src ile saldırı yüzeyini daraltırsınız.

Bir sonraki adım: Uygulamanıza Report-Only CSP ekleyin, 3 gün ihlalleri toplayın ve ardından gerçek CSP’ye geçin. Deneyiminizi yorumlarda paylaşın: Hangi direktif sizi en çok zorladı, hangi üçüncü parti servisler policy’yi deldi?