XSS Nedir? Türleri ve Korunma Yolları
XSS (Cross-Site Scripting), saldırganın kontrol ettiği içeriğin bir web sitesinde betik olarak çalışıp ziyaretçinin tarayıcısında o sitenin kodu gibi davranmasıdır. Üç ana türü vardır: stored, reflected ve DOM tabanlı. Korunmanın temeli bağlama uygun çıktı kodlamadır; CSP, HttpOnly çerez ve Trusted Types ek katman olarak çalışır.
Bir yorum kutusu, bir arama sonucu sayfası ya da bir profil adı. Uygulama bu metni sayfaya basarken tarayıcıya kod olarak yorumlatıyorsa ziyaretçi risk altındadır. Bu yazıda XSS'in nasıl oluştuğunu, üç türünü ve gerçek vakaları göreceksin. Ağırlık savunmada: hangi katman neyi keser, hangi sırayla kurulur.
XSS nedir?
XSS (Cross-Site Scripting, siteler arası betik çalıştırma), saldırganın kontrol ettiği içeriğin bir sitede betik olarak çalışmasıdır. Tarayıcı betiğin siteden mi saldırgandan mı geldiğini ayırt edemez. Betik, sitenin çerezlerine, sayfadaki verilere ve kullanıcı adına işlem yapma gücüne erişir.
PortSwigger, XSS'i aynı köken kuralını (same-origin policy) dolanan bir açık olarak tanımlar. MITRE bu açığı CWE-79 koduyla tanımlar. MITRE'nin 2025 CWE Top 25 listesinde XSS yine birinci sırada. OWASP Top 10 2025'te XSS, A05 Enjeksiyon kategorisinin içinde yer alır. OWASP'a göre XSS tek başına 30 binden fazla CVE kaydı taşır.
XSS nasıl oluşur?
XSS, kullanıcıdan gelen bir değer sayfaya kod olarak yorumlanabilecek bir yerden yazıldığında oluşur. Bu yer sunucu şablonunda kaçışsız basılan bir değişken olabilir. JavaScript'te innerHTML özelliğine verilen bir metin de olabilir.
// Zafiyetli desen: URL'deki değer HTML olarak yorumlanıyor
const q = new URLSearchParams(location.search).get("q");
document.getElementById("baslik").innerHTML = "Aranan: " + q;
Kod normal aramalarda sorunsuz çalışır. Ama değer HTML etiketi içerirse tarayıcı onu metin olarak değil, sayfanın parçası olarak işler. Düzeltmesi tek satırdır:
// Güvenli desen: değer düz metin olarak yazılıyor
const q = new URLSearchParams(location.search).get("q");
document.getElementById("baslik").textContent = "Aranan: " + q;
textContent, değeri her zaman düz metin olarak yazar. OWASP XSS Prevention Cheat Sheet bu tür API'lere güvenli hedef (safe sink) der. innerHTML, document.write() ve eval() ise tehlikeli hedeflerdir.
XSS türleri nelerdir?
XSS üç ana türe ayrılır: kalıcı (stored), yansıyan (reflected) ve DOM tabanlı. Ayrım, zararlı içeriğin nerede durduğuna ve onu sayfaya hangi kodun taşıdığına göre yapılır.
| Özellik | Stored XSS | Reflected XSS | DOM tabanlı XSS |
|---|---|---|---|
| İçerik nerede durur? | Veritabanında: yorum, profil, ürün adı. | Hiçbir yerde, o anki isteğin içinde gelir. | Tarayıcıda: URL parçası, postMessage, localStorage. |
| Kimi etkiler? | Sayfayı açan herkesi. | Hazırlanmış bağlantıya tıklayanı. | Hazırlanmış bağlantıyı ya da veriyi açanı. |
| Sunucu zararlı içeriği görür mü? | Evet, kaydederken. | Evet, isteği işlerken. | Çoğu zaman hayır. |
| Açık nerede? | Sunucu çıktısında. | Sunucu çıktısında. | İstemci tarafı JavaScript'te. |
| Bugcrowd VRT önceliği | Ayrıcalıksız kullanıcıdan herkese: P2. | Başkasını etkileyen: P3. | Ayrı satır yok, etkiye göre. |
| Kalıcı çözüm | Çıktı kodlama, gerekirse HTML temizleme. | Bağlama uygun çıktı kodlama. | Güvenli DOM API'leri ve Trusted Types. |
Bu üç türün yanında üç ad daha duyarsın. Kör XSS (blind XSS), saldırganın göremediği bir ekranda, örneğin yönetim panelinde tetiklenen kalıcı XSS'tir. Self-XSS yalnız kişinin kendisini etkiler. Bugcrowd'un Temmuz 2026 tarihli Vulnerability Rating Taxonomy sürümünde self-XSS en düşük öncelik olan P5'tir. Mutasyon XSS (mXSS) ise temizlenmiş HTML'in tarayıcı ayrıştırırken yeniden biçim değiştirmesinden doğar.
DOM tabanlı XSS'in sinsi bir yanı var. URL'nin diyez işaretinden sonraki kısmı sunucuya hiç gitmez. Zararlı değer orada taşınırsa sunucu logunda iz kalmayabilir.
XSS ile saldırgan ne yapabilir?
XSS ile saldırgan, kurbanın oturumunda kurbanın yapabildiği her şeyi yapabilir. Etki kurbanın yetkisine bağlıdır. Sıradan kullanıcıda profil verisi, yöneticide bütün panel risktedir.
- Kullanıcı adına istek göndermek: parola değiştirme, e-posta güncelleme, transfer formu.
- Sayfadaki hassas veriyi okumak: mesajlar, adresler, CSRF jetonları.
- Sahte bir giriş formu göstermek ve yazılan parolayı toplamak.
- HttpOnly olmayan oturum çerezlerini okumak.
- Kendini kopyalayan bir solucan başlatmak.
Gerçek XSS vakaları nelerdir?
En bilinen XSS vakası, 2005'te MySpace'te yayılan Samy solucanıdır. Bazı ünlü olaylar ise yanlışlıkla XSS diye anılır. Aşağıdaki tablo vakaları doğru sınıfıyla verir.
| Vaka | Yıl | Gerçek sınıfı | Ne oldu? |
|---|---|---|---|
| Samy solucanı, MySpace | 2005 | Kalıcı XSS. | Yirmi saatte bir milyondan fazla profile yayıldı. |
| TweetDeck | 2014 | Kalıcı XSS. | Bir tweet kendini 80 binden fazla kez yeniden paylaştı. |
| British Airways | 2018 | XSS değil: sunucu ele geçirme ve betik değiştirme. | Ödeme sayfasındaki kart verisi kopyalandı. |
Samy solucanını 4 Ekim 2005'te 19 yaşındaki Samy Kamkar yazdı. Kamkar, MySpace profilinin filtresini atlatan kalıcı bir XSS buldu. Profili görüntüleyen her kullanıcının profiline aynı kod kopyalandı. Yirmi saat içinde bir milyondan fazla kullanıcı etkilendi. Kamkar 2007'de suçlamayı kabul etti ve üç yıl denetimli serbestlik cezası aldı.
TweetDeck olayı 11 Haziran 2014'te yaşandı. Twitter'ın masaüstü istemcisi, kalp simgesi içeren tweetlerde HTML kaçışını atlıyordu. Bu hatayı kullanan bir tweet, görüntüleyen herkesin hesabından kendiliğinden yeniden paylaşıldı. The Register'a göre tweet 80 binden fazla kez paylaşıldı. Twitter, yama çıkana kadar hizmeti fiilen durdurdu.
British Airways vakası ise sık sık XSS örneği diye anlatılır, ama değildir. Saldırgan bir tedarikçi çalışanının çalıntı hesabıyla ağa girdi. Hesapta çok faktörlü doğrulama yoktu. Sonra sitenin ödeme sayfasında çalışan bir JavaScript dosyasını değiştirdi. RiskIQ, saldırıyı Magecart adlı kart kopyalama gruplarına bağladı.
İngiltere'nin veri koruma otoritesi ICO'ya göre yaklaşık 429.612 müşteri ve çalışanın verisi etkilendi. Saldırı 22 Haziran 2018'de başladı. BA durumu 5 Eylül'de üçüncü bir taraftan öğrendi. ICO, Ekim 2020'de 20 milyon sterlin ceza kesti. Burada girdi kaynaklı bir XSS yok; savunma da farklı. Çok faktörlü doğrulama, dosya bütünlüğü izleme ve üçüncü taraf betikler için Subresource Integrity (SRI) öne çıkar.
XSS'ten nasıl korunulur?
XSS'e karşı birinci savunma, veriyi yazıldığı bağlama uygun biçimde kodlamaktır. CSP, HttpOnly çerez ve Trusted Types bunun arkasına konan ek katmanlardır. MDN de OWASP da aynı uyarıyı yapar: CSP, girdiyi doğru işlemenin yerini tutmaz.
Bağlama uygun çıktı kodlama nedir?
Aynı değer, yazıldığı yere göre farklı kodlama ister. OWASP'ın önerdiği eşleşme şöyle:
- HTML gövdesi: HTML varlık kodlaması, örneğin
<biçimi. - HTML özniteliği: değeri tırnak içine al ve öznitelik kodlaması uygula.
- JavaScript: değeri yalnız tırnaklı bir dizge içine, JavaScript kodlamasıyla koy.
- CSS: yalnız özellik değerine, CSS onaltılık kodlamasıyla yaz.
- URL: parametre değerine yüzde kodlaması uygula.
Kodlama fonksiyonunu elle yazma. Kullandığın dilin ya da şablon motorunun hazır fonksiyonunu kullan.
Framework'ün otomatik kaçışı yeterli mi?
React, Vue, Angular ve Django şablonları değeri varsayılan olarak kaçışlar. Bu, XSS'in büyük kısmını otomatik keser. Açık genelde kaçış kapılarında doğar:
- React'te
dangerouslySetInnerHTMLözelliği. - Vue'da
v-htmlyönergesi. - Angular'da
bypassSecurityTrustHtmlve benzeri fonksiyonlar. - Django'da
safefiltresi vemark_safe()fonksiyonu. - Kullanıcı girdisinin, şema denetimi yapılmadan bir bağlantı adresine konması.
Django belgeleri de otomatik kaçışın her bağlamda korumadığını yazar. Örneğin tırnaksız bir öznitelik değeri açık bırakabilir. Kod incelemesinde bu kapıları tek tek işaretle.
Kullanıcının HTML yazması gerekiyorsa ne yapmalı?
Blog editörü ya da e-posta şablonu gibi yerlerde HTML'i kodlamak işe yaramaz, temizlemek gerekir. OWASP bu iş için DOMPurify kütüphanesini önerir. DOMPurify tehlikeli etiket ve öznitelikleri atar, zararsız biçimlendirmeyi bırakır.
import DOMPurify from "dompurify"; const temizHtml = DOMPurify.sanitize(kullaniciHtml); yorumKutusu.innerHTML = temizHtml;
OWASP'ın bir uyarısı var: temizledikten sonra içeriği değiştirirsen temizliği boşa çıkarabilirsin. Temizleme, sayfaya yazmadan önceki son adım olsun. Kütüphaneyi de güncel tut.
CSP nasıl kurulur?
CSP (Content Security Policy), tarayıcıya hangi betiklerin çalışabileceğini söyleyen bir HTTP başlığıdır. Bir XSS açığı kalsa bile saldırganın betiği politikaya uymadığı için çalışmayabilir. MDN'in önerdiği katı (strict) politikanın nonce tabanlı hâli şöyle:
Content-Security-Policy: script-src 'nonce-RASTGELE_DEGER'; object-src 'none'; base-uri 'none'
Nonce, her yanıtta yeniden üretilen rastgele bir değerdir. Sayfadaki meşru betik etiketleri aynı değeri taşır. Taşımayan betik çalışmaz. Statik sitelerde nonce yerine betiğin özetiyle (hash) çalışan sürüm kullanılır.
Yeni politikayı doğrudan uygulamadan önce Content-Security-Policy-Report-Only başlığıyla dene. Bu modda tarayıcı ihlali engellemez, yalnız raporlar. Böylece kırılan sayfaları canlıya geçmeden görürsün.
Çerez ayarları XSS'te ne işe yarar?
HttpOnly bayrağı, oturum çerezini JavaScript'in okuyamayacağı hâle getirir. Açık kalsa bile saldırgan çerezi kopyalayıp başka bir cihazda kullanamaz.
Set-Cookie: oturum=RASTGELE_KIMLIK; HttpOnly; Secure; SameSite=Lax; Path=/
Ama HttpOnly XSS'i engellemez. Betik kurbanın tarayıcısında çalışırken kurban adına istek atmayı sürdürebilir. Bu yüzden HttpOnly'yi etkiyi küçülten bir katman olarak gör.
Trusted Types nedir?
Trusted Types, DOM tabanlı XSS'i kaynağında kesen bir tarayıcı API'sidir. CSP'ye require-trusted-types-for 'script' eklenince innerHTML gibi tehlikeli hedefler düz metin kabul etmez. Değer önce senin tanımladığın bir politikadan geçmek zorundadır.
const politika = trustedTypes.createPolicy("temizleyici", {
createHTML: (girdi) => DOMPurify.sanitize(girdi),
});
yorumKutusu.innerHTML = politika.createHTML(kullaniciHtml);
MDN'e göre Trusted Types, Şubat 2026'dan beri güncel ana tarayıcıların hepsinde çalışıyor. Eski tarayıcılar için hafif bir yedek betik (tinyfill) kullanılabilir. Büyük kod tabanında asıl kazanç şudur: tehlikeli her kullanım hata verir ve gözden kaçmaz.
Savunmayı hangi sırayla kurmalısın?
Çalışan bir uygulamada XSS savunmasını şu sırayla kurmak, en az emekle en çok riski düşürür:
- Şablon motorunun otomatik kaçışının açık olduğunu doğrula.
- Kod tabanında kaçış kapılarını ara: dangerouslySetInnerHTML, v-html, innerHTML, safe filtresi.
- Her birini güvenli bir API'ye çevir ya da DOMPurify'dan geçir.
- Oturum çerezlerine HttpOnly, Secure ve SameSite ekle.
- CSP'yi önce Report-Only modunda yayınla ve raporları birkaç hafta izle.
- Politikayı zorunlu moda al, ardından Trusted Types'ı ekle.
- Yeni kaçış kapılarını pull request aşamasında bir SAST kuralıyla yakala.
XSS neden hâlâ bu kadar yaygın?
XSS yaygın, çünkü her yeni özellik veriyi sayfaya yazmanın yeni bir yolunu açar. HackerOne'ın 8. Hacker-Powered Security Report'una göre XSS, bug bounty programlarında en çok bildirilen açık türü. Aynı raporda XSS bildirimlerinin 2023'e göre yüzde 10 azaldığı da yazıyor.
HackerOne'ın 2025 tarihli 9. raporu tabloyu biraz daha netleştiriyor. Rapora göre XSS bildirimleri neredeyse yerinde sayıyor. Otomatik ajanların (hackbot) geçerli bulgularının yüzde 78'i XSS. Yani XSS, kalıp tanıyan araçların da kolay yakaladığı bir açık. Bug bounty'de bu açığı arayacaksan en sık bulunan 10 açık yazımıza da göz at.
XSS'i nerede güvenle öğrenirsin?
XSS'i yalnız sana ait ya da test izni verilmiş sistemlerde dene. İzinsiz test, TCK'nın bilişim suçları bölümüne (md. 243-245) girer.
AltaySec Akademi'deki Web Uygulama Güvenliği yolu, XSS'i enjeksiyon ailesinin tarayıcıdaki üyesi olarak ele alır. XSS dersi bağlamları tek tek açar. Bağlamı Kıran Tırnak labında yansıyan XSS'i izinli bir hedefte görürsün. Saha bölümündeki web savunması görevlerinden "Sunucunun Görmediği Parça", DOM tabanlı XSS ile CSP'yi birlikte çalıştırır. Kod tarafı için bağlama göre çıktı kodlama dersine geç.
Kategorinin geniş haritası OWASP Top 10 2025 yazımızda. Sunucu tarafındaki kardeş açık için SQL injection yazısını oku. XSS'ten sonra sıradaki mantıklı konu CSRF.
Kaynaklar
Sık sorulan sorular
XSS ile SQL injection arasındaki fark nedir?
İkisi de enjeksiyon ailesindendir ama farklı yorumlayıcıyı hedefler. SQL injection sunucudaki veritabanı sorgusunu bozar ve veriyi doğrudan hedef alır. XSS ise kullanıcının tarayıcısında çalışır ve kurbanın oturumunu kullanır. Savunmaları da farklıdır: SQL injection için parametreli sorgu, XSS için bağlama uygun çıktı kodlama gerekir.
HttpOnly çerez XSS'i engeller mi?
Engellemez, yalnız etkisini sınırlar. HttpOnly bayrağı oturum çerezinin JavaScript ile okunmasını önler. Saldırgan çerezi çalıp başka bir cihazda kullanamaz. Ama zararlı betik kurbanın tarayıcısında çalışırken kurban adına istek atabilir ve sayfadaki veriyi okuyabilir. Asıl çözüm çıktı kodlamadır; HttpOnly ek bir katmandır.
React ya da Vue kullanan bir sitede XSS olur mu?
Olur, ama daha seyrek görülür. Bu framework'ler değeri varsayılan olarak kaçışlar. Açık genelde geliştiricinin bilerek açtığı kapılarda doğar: React'te dangerouslySetInnerHTML, Vue'da v-html, şema denetimi olmadan bağlantı adresine konan girdi ya da üçüncü taraf bir bileşen. Bu noktaları kod incelemesinde işaretle ve gerekiyorsa DOMPurify'dan geçir.
CSP tek başına XSS'i önler mi?
Önlemez. MDN ve OWASP, CSP'yi girdi işleme ve çıktı kodlamanın yerine değil, arkasına konan ikinci hat olarak tanımlar. İyi kurulmuş, nonce ya da hash tabanlı katı bir politika birçok saldırıyı boşa çıkarır. Ama satır içi betiklere toptan izin veren gevşek bir politika pek işe yaramaz.
Self-XSS bug bounty'de ödül alır mı?
Genellikle almaz. Bugcrowd'un 2026 sürümü Vulnerability Rating Taxonomy listesinde yalnız kişinin kendisini etkileyen self-XSS en düşük öncelik olan P5 seviyesindedir. Açığın değer kazanması için başka bir kullanıcıya taşınabilmesi gerekir. Örneğin CSRF ile zincirlenip kurbanın hesabında tetiklenebiliyorsa önem derecesi yükselebilir. Raporda bu zinciri açıkça göster.
- xss nedir
- cross site scripting nedir
- xss türleri
- web güvenliği
- owasp