2026-08-12

XSS Nedir ve Nasıl Önlenir? Web Güvenliği ve Savunma

Cross-site scripting (XSS) saldırıları nasıl çalışır? Stored, reflected ve DOM XSS türleri, CSP kuralları ve HTML encoding ile güvenlik rehberi.

securityweb-developmenthtmlcybersecurity
  • Cross-Site Scripting (XSS), istemci tarafında yetkisiz JavaScript kodlarının diğer kullanıcıların tarayıcısında çalıştırılmasına yol açan bir güvenlik açığıdır.
  • Stored (Kalıcı), Reflected (Yansıtılan) ve DOM-based olmak üzere üç ana türe ayrılır; en yüksek etki kalıcı veritabanı kayıtlarından doğar.
  • Bağlama duyarlı çıktı kodlaması (context-aware output encoding) ve DOM manipülasyonunda güvenli API kullanımı temel savunma hattıdır.
  • Content Security Policy (CSP) başlıkları ve HttpOnly çerez bayrakları çok katmanlı savunmanın tamamlayıcı parçalarıdır.

Cross-Site Scripting (XSS), web uygulamalarında istemci güvenliğini doğrudan tehdit eden en yaygın güvenlik açıklarındandır. Açığın temel sebebi, güvenilmeyen kullanıcı verilerinin HTML belgesine doğrudan yerleştirilmesi ve tarayıcının bu veriyi çalıştırılabilir bir script olarak yorumlamasıdır. Saldırgan, kurbanın tarayıcısında kendi yazdığı JavaScript kodunu çalıştırdığında oturum çerezlerini çalabilir, oturumu ele geçirebilir veya kullanıcının adına yetkisiz işlemler gerçekleştirebilir.

Tarayıcılar bir kaynaktan indirilen betiğe tam güven duyar. Betik çalıştığı anda localStorage, sessionStorage, DOM düğümleri ve aynı etki alanına ait kimlik doğrulama belirteçlerine doğrudan erişir.

XSS Türleri ve Çalışma Mekanizmaları

XSS zafiyetleri verinin depolanma ve tarayıcıya iletilme yöntemine göre üç temel kategoriye ayrılır:

| XSS Türü | Verinin Kaynağı | Yürütme Konumu | Risk Seviyesi | |---|---|---|---| | Stored (Kalıcı / Persistent) | Veritabanı veya sunucu depolama alanı | Sayfayı ziyaret eden tüm kullanıcılar | Kritik | | Reflected (Yansıtılan) | HTTP istek parametreleri veya URL | Yalnızca zararlı linke tıklayan kullanıcı | Yüksek | | DOM-Based | URL hash, document.referrer veya istemci verisi | İstemci tarafındaki güvensiz JavaScript çağrıları | Yüksek |

Stored XSS en tehlikeli türdür. Saldırgan bir blog yorumuna, profil açıklamasına veya destek talebine zararlı bir script etiketi bırakır. Bu veri sunucu veritabanına kaydedilir ve ilgili sayfayı açan her kullanıcıya filtrelenmeden iletilir. Bu mekanizma nedeniyle saldırı tek bir kullanıcıyla sınırlı kalmaz, sayfayı görüntüleyen tüm ziyaretçileri eşzamanlı olarak etkiler.

Reflected XSS türünde zararlı girdi veritabanında saklanmaz. Arama kutusu veya hata mesajı parametresi üzerinden URL içine gömülür (/search?q=payload). Kullanıcı bu bağlantıyı açtığında sunucu girdiyi HTML yanıtının içine doğrudan geri yansıtır.

DOM-Based XSS ise sunucuya hiç uğramadan tamamen tarayıcı içinde gerçekleşir. İstemci tarafındaki JavaScript kodu, URL parçalarını (location.hash, location.search) okuyup innerHTML veya document.write gibi güvensiz fonksiyonlara aktardığında açık tetiklenir.

Güvensiz Kodlama Örnekleri

İstemci tarafında güvensiz DOM manipülasyonu yapıldığında XSS açığı saniyeler içinde ortaya çıkar:

// Güvensiz DOM manipülasyonu: DOM XSS üretir
const params = new URLSearchParams(window.location.search);
const userName = params.get('name');

// innerHTML kullanıcı girdisini ayrıştırıp script çalıştırır
document.getElementById('welcome-banner').innerHTML = 'Hoş geldin, ' + userName;

Saldırgan URL adresine onerror olay dinleyicisi barındıran bir görsel etiketi veya script yükü eklediğinde tarayıcı bu kodu derhal çalıştırır.

Bu tür durumlarda innerHTML yerine textContent veya innerText kullanıldığında tarayıcı girdiyi hiçbir zaman HTML etiketi olarak işlemez:

// Güvenli yöntem: Girdi yalnızca düz metin olarak eklenir
const safeBanner = document.getElementById('welcome-banner');
safeBanner.textContent = 'Hoş geldin, ' + userName;

Özel karakterlerin tarayıcıda kod parçası olarak yorumlanmasını engellemek için HTML varlık kodlayıcı aracıyla girdi dönüşümü yapabilir, sayfa yapısındaki DOM hiyerarşisini düzenlemek için HTML formatlayıcı yardımcısını kullanabilirsiniz.

Bağlama Duyarlı Çıktı Kodlaması (Context-Aware Encoding)

Bir veriyi ekrana basarken doğru kodlama yöntemi, verinin HTML belgesinin neresine yerleştirileceğine bağlıdır. Yanlış bağlamda yapılan kodlama koruma sağlamaz:

  • HTML Gövde Metni: Standart karakterler HTML varlıklarına dönüştürülür (< karakteri &lt;, > karakteri &gt;, & karakteri &amp;, " karakteri &quot;, ' karakteri &#x27; olur).
  • HTML Nitelik Değerleri: Çift ve tek tırnaklar mutlak biçimde kodlanmalıdır. Aksi halde saldırgan tırnağı kapatıp yeni bir olay dinleyicisi (onload, onfocus) ekler.
  • JavaScript Değişken Alanları: Kullanıcı verisi doğrudan betik bloklarına gömülmemelidir. JSON serileştirmesi yapılmalı ve kapanış etiketini içeren dizilimler (\u003C) biçiminde kaçırılmalıdır.
  • URL Bağlantı Alanları: Girdi javascript: veya data: protokolüyle başlıyorsa filtrelenmeli, yalnızca http: veya https: protokollerine izin verilmelidir.

Sunucu taraflı injection risklerini kapatırken uygulanan yöntemler için SQL injection rehberi içeriğindeki parametrelendirme mantığı geçerlidir; istemci tarafında ise bağlama duyarlı kodlama esastır.

Content Security Policy (CSP) ile Çok Katmanlı Koruma

Kodlama hataları gözden kaçsa dahi tarayıcı düzeyinde yürütmeyi sınırlayan en güçlü savunma mekanizması Content Security Policy (CSP) başlığıdır. CSP, sunucunun HTTP yanıt başlığı (Content-Security-Policy) üzerinden tarayıcıya hangi kaynaklardan betik yüklenebileceğini bildirmesini sağlar.

Güvenli bir CSP yapılandırması:

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

Bu kural kümesi şu sınırları çizer:

  • unsafe-inline engeli: HTML içine doğrudan yazılmış satır içi betiklerin ve olay dinleyicilerinin çalışmasını tamamen durdurur.
  • Nonce doğrulaması: Yalnızca sunucunun o anki HTTP isteği için ürettiği rastgele ve tek kullanımlık nonce değerine sahip betik etiketleri yürütülür.
  • object-src 'none': Flash ve Java eklentileri gibi eski vektörleri kapatır.

Çerez Güvenliği ve Modern Framework Yaklaşımları

Kritik oturum çerezleri için HttpOnly bayrağı tanımlanmalıdır. HttpOnly olarak işaretlenen bir çereze JavaScript üzerinden (document.cookie) erişilemez. Saldırgan sayfada kod çalıştırsa bile oturum çerezini doğrudan çalamaz.

React, Vue ve Angular gibi modern kütüphaneler JSX veya şablon bağlamalarında ({userName}) varsayılan olarak HTML encode uygular. Ancak bu kütüphanelerde dangerouslySetInnerHTML, v-html veya [innerHTML] gibi kaçış noktaları kullanıldığında zafiyet aynen devam eder. Bu tür zafiyetli fonksiyonlar zorunlu olduğunda girdi DOMPurify gibi bir temizleme (sanitization) kütüphanesinden geçirilmelidir.

Sıkça Sorulan Sorular

Modern frontend kütüphaneleri XSS açığını tamamen bitirir mi?

Bitirmez. React veya Vue standart değişken bağlamalarında HTML karakterlerini otomatik olarak kodlar; fakat dangerouslySetInnerHTML, v-html gibi ham HTML fonksiyonları veya href="javascript:..." gibi URL protokol enjeksiyonları kullanıldığında XSS açığı oluşur.

HttpOnly bayrağı XSS saldırılarını tamamen durdurur mu?

Hayır. HttpOnly bayrağı çerezin document.cookie üzerinden okunmasını engeller. Ancak sayfada çalışan zararlı JavaScript, kurbanın oturumu üzerinden arka planda istek (fetch veya XHR) atarak yetkisiz işlemler yapabilir veya arayüze sahte form yerleştirerek kimlik bilgilerini toplayabilir.

Basit bir regex ile script etiketlerini silmek güvenli midir?

Güvenli değildir. XSS yalnızca temel betik etiketleriyle sınırlı değildir. Görsel etiketlerindeki onerror, SVG içindeki onload, iframe bağlantıları veya CSS stilleri içine gömülen JavaScript vektörleri regex filtrelerini atlatır. Çözüm etiket ayıklamak değil, tam karakter kodlaması veya DOMPurify gibi test edilmiş temizleme kütüphaneleri kullanmaktır.

CSP başlığı tek başına tüm XSS risklerini çözer mi?

Çözmez. CSP güçlü bir ikinci savunma hattıdır; ancak yanlış yapılandırılmış kurallar (unsafe-inline veya geniş wildcard kullanımı) korumayı zayıflatır. Birincil savunma her zaman girdi doğrulama ve bağlama duyarlı çıktı kodlamasıdır.