- Konu sahibi
- #1
DOM tabanlı XSS, güvenilmeyen verinin tarayıcıdaki JavaScript tarafından çalıştırılabilir bir bağlama güvensiz biçimde aktarılmasıyla oluşur. Veri URL’den, istemci depolamasından veya sunucunun verdiği bir yanıttan gelebilir; sunucuya hiç gitmemesi tanımın zorunlu koşulu değildir. En yaygın akış; URL, form alanı veya başka bir istemci tarafı kaynaktan alınan verinin
Bir DOM XSS açığı genellikle üç parçadan oluşur:
Sunucu bu akışın dışında kalabildiği için saldırı isteği sunucu günlüklerinde görünmeyebilir. Açık, sayfanın JavaScript kodu çalıştırıldığında ve saldırgan kontrollü veri DOM'a yerleştirildiğinde ortaya çıkar.
Bir arama sayfası, URL'deki sorguyu sonuç başlığında göstermek istesin:
Bu kod,
Güvenli yaklaşım, amaç yalnızca metin göstermekse
Bu sürümde kullanıcı verisi HTML olarak yorumlanmaz; etiket benzeri karakterler ekranda metin olarak görünür. Beklenen sonuç, girdinin çalışmaması ve olduğu gibi yazı olarak gösterilmesidir. Girdi sayfada hiç görünmüyorsa önce parametre adını, JavaScript'in çalışıp çalışmadığını ve hedef elementin mevcut olup olmadığını kontrol edin. Bu düzeltme yalnızca bu veri akışını düzeltir; uygulamadaki diğer HTML eklemelerini otomatik olarak güvenli hale getirmez.
Aşağıdaki ayrım, düzeltme kararını kolaylaştırır:
Buradaki kararın temeli, verinin gerçekten HTML olmasına ihtiyaç olup olmadığıdır. İhtiyaç yoksa temizleme yerine HTML yorumlamayan bir API'ye geçmek daha doğrudan ve daha az hatalıdır.
URL kodlamasının tek başına çözüm olduğu sanılır; URL kodlama, verinin HTML bağlamında güvenli kullanılacağını garanti etmez. Yalnızca sunucu tarafında filtre uygulamak da yeterli değildir, çünkü DOM XSS verisi sunucuya hiç gitmeyebilir.
Yansıtılmış/stored ayrımı verinin nasıl geldiğini, DOM tabanlı ayrımı ise güvensiz işlemenin istemcide oluşmasını anlatır; bu sınıflar bütünüyle birbirini dışlamaz. Yansıtılmış XSS'te sunucu, saldırgan kontrollü veriyi yanıt içeriğine yansıtabilir. DOM XSS'te ise güvenlik sorunu çoğunlukla tarayıcıda çalışan JavaScript'in veriyi DOM'a nasıl aktardığından kaynaklanır; sunucunun veriyi yanıtlaması şart değildir.
Hayır. Uygun bir Content Security Policy bazı çalıştırma yollarını sınırlayabilir, ancak güvensiz DOM veri akışını düzeltmez. Asıl düzeltme, güvenilmeyen veriyi doğru bağlamda kodlamak veya HTML yorumlamayan DOM API'leri kullanmaktır.
innerHTML, outerHTML ya da document.write() gibi HTML yorumlayan bir hedefe aktarılmasıdır. Tarayıcı bu veriyi metin olarak değil, HTML veya çalıştırılabilir içerik olarak işler.Nasıl çalışır?
Bir DOM XSS açığı genellikle üç parçadan oluşur:
- Kullanıcı tarafından değiştirilebilen bir kaynak seçilir. Örneğin
location.hash,location.search,document.referrerveya bir form alanı. - Kod, bu veriyi doğrulamadan veya uygun şekilde kodlamadan işler.
- Veri, HTML yorumlayan bir hedefe aktarılır. Örneğin
innerHTMLveyainsertAdjacentHTML().
Sunucu bu akışın dışında kalabildiği için saldırı isteği sunucu günlüklerinde görünmeyebilir. Açık, sayfanın JavaScript kodu çalıştırıldığında ve saldırgan kontrollü veri DOM'a yerleştirildiğinde ortaya çıkar.
Somut varsayımsal örnek
Bir arama sayfası, URL'deki sorguyu sonuç başlığında göstermek istesin:
Kod:
<div id="result"></div>
<script>
const query = new URLSearchParams(location.search).get('q') || '';
document.querySelector('#result').innerHTML = 'Arama: ' + query;
</script>
Bu kod,
q parametresini HTML olarak yorumlar. innerHTML ile eklenen her script etiketi mutlaka çalışmaz; olay işleyicileri gibi başka çalıştırma yolları da bulunduğundan bu durum güvenli olduğu anlamına gelmez. Kullanıcı parametreye HTML etiketleri veya olay işleyicisi içeren bir değer verdiğinde, veri #result içine HTML olarak eklenebilir ve tarayıcı bunu çalıştırabilir. Sorun, değerin URL'den gelmesi değil, HTML yorumlayan hedefe güvenilmeyen biçimde aktarılmasıdır.Güvenli yaklaşım, amaç yalnızca metin göstermekse
textContent kullanmaktır:
Kod:
<div id="result"></div>
<script>
const query = new URLSearchParams(location.search).get('q') || '';
document.querySelector('#result').textContent = 'Arama: ' + query;
</script>
Bu sürümde kullanıcı verisi HTML olarak yorumlanmaz; etiket benzeri karakterler ekranda metin olarak görünür. Beklenen sonuç, girdinin çalışmaması ve olduğu gibi yazı olarak gösterilmesidir. Girdi sayfada hiç görünmüyorsa önce parametre adını, JavaScript'in çalışıp çalışmadığını ve hedef elementin mevcut olup olmadığını kontrol edin. Bu düzeltme yalnızca bu veri akışını düzeltir; uygulamadaki diğer HTML eklemelerini otomatik olarak güvenli hale getirmez.
Aşağıdaki ayrım, düzeltme kararını kolaylaştırır:
| Amaç | Riskli tercih | Tercih edilmesi gereken yaklaşım |
|---|---|---|
| Düz metin göstermek | innerHTML | textContent veya innerText |
| Önceden tanımlı HTML oluşturmak | Kullanıcı verisini doğrudan birleştirmek | Sabit şablon ve ayrı DOM düğümleri kullanmak |
| Kullanıcıya sınırlı HTML sunmak | Elle filtre yazmak | Güvenilir bir HTML temizleyiciyle izin verilen öğe ve öznitelikleri sınırlamak |
Buradaki kararın temeli, verinin gerçekten HTML olmasına ihtiyaç olup olmadığıdır. İhtiyaç yoksa temizleme yerine HTML yorumlamayan bir API'ye geçmek daha doğrudan ve daha az hatalıdır.
Uygulanabilir kontrol ve düzeltme adımları
- Kullanıcı kontrollü kaynakları bulun:
location,document.referrer,postMessage, form değerleri ve istemci tarafı depolama alanlarını inceleyin. - Bu değerlerin izini sürerek
innerHTML,outerHTML,insertAdjacentHTML,document.write,evalve benzeri hedeflere ulaşıp ulaşmadığını kontrol edin. - Yalnız metin gerekiyorsa hedef API'yi
textContentile değiştirin. Sabit HTML gerekiyorsa HTML iskeletini kodda ayrı oluşturup kullanıcı verisini metin düğümü olarak ekleyin. - HTML desteği zorunluysa yalnızca izin verilen etiket, öznitelik ve URL şemalarını kabul eden güvenilir bir temizleme çözümü kullanın. Elle birkaç karakteri değiştirmek kapsamlı koruma sayılmaz.
- Düzeltmeyi uygulamanın gerçekten kullandığı kaynak üzerinden test edin. Bu örnekte
?q=%3Cb%3Eornek%3C%2Fb%3Egibi zararsız bir biçimlendirme girdisi, düzeltilmiş sürümde kalın yazı değil etiketleriyle düz metin görünmelidir. Parça veya form verisi kullanan başka akışlar varsa onları da ayrıca inceleyin. Beklenen sonuç, girdinin çalışmaması ve güvenli bağlamda metin olarak kalmasıdır. - Tarayıcı geliştirici araçlarında DOM'u ve konsolu kontrol edin. Değer sunucudan dönmese bile istemci tarafında hedefe aktarılıyorsa sorun devam ediyor demektir.
Sık yapılan hatalar
URL kodlamasının tek başına çözüm olduğu sanılır; URL kodlama, verinin HTML bağlamında güvenli kullanılacağını garanti etmez. Yalnızca sunucu tarafında filtre uygulamak da yeterli değildir, çünkü DOM XSS verisi sunucuya hiç gitmeyebilir.
innerHTML yerine başka bir HTML yorumlayan API'ye geçmek de gerçek düzeltme değildir. Ayrıca yalnızca görünen arama alanını düzeltip aynı kaynağın başka bir DOM hedefine aktarıldığı kod yollarını bırakmak açığı sürdürebilir.Kaynaklar
Sık sorulan sorular
DOM XSS ile yansıtılmış XSS arasındaki temel fark nedir?
Yansıtılmış/stored ayrımı verinin nasıl geldiğini, DOM tabanlı ayrımı ise güvensiz işlemenin istemcide oluşmasını anlatır; bu sınıflar bütünüyle birbirini dışlamaz. Yansıtılmış XSS'te sunucu, saldırgan kontrollü veriyi yanıt içeriğine yansıtabilir. DOM XSS'te ise güvenlik sorunu çoğunlukla tarayıcıda çalışan JavaScript'in veriyi DOM'a nasıl aktardığından kaynaklanır; sunucunun veriyi yanıtlaması şart değildir.
Content Security Policy DOM XSS'i tamamen ortadan kaldırır mı?
Hayır. Uygun bir Content Security Policy bazı çalıştırma yollarını sınırlayabilir, ancak güvensiz DOM veri akışını düzeltmez. Asıl düzeltme, güvenilmeyen veriyi doğru bağlamda kodlamak veya HTML yorumlamayan DOM API'leri kullanmaktır.