DOM tabanlı siteler arası komut dosyası çalıştırma (DOM XSS), kullanıcı tarafından kontrol edilen bir kaynaktan (ör. kullanıcı adı veya URL parçasından alınan bir yönlendirme URL'si) gelen veriler, rastgele JavaScript kodu çalıştırabilen eval()
gibi bir işlev veya .innerHTML
gibi bir özellik ayarlayıcı olan havuza ulaştığında gerçekleşir.
DOM XSS, en yaygın web güvenliği açıklarından biridir ve geliştirme ekiplerinin uygulamalarına yanlışlıkla eklemesi yaygın bir durumdur. Trusted Types, tehlikeli web API işlevlerini varsayılan olarak güvenli hale getirerek uygulamaları DOM XSS güvenlik açıklarından arındırmak, güvenlik açısından incelemek ve yazmak için gereken araçları sağlar. Güvenilir Türler, henüz desteklemeyen tarayıcılar için polyfill olarak kullanılabilir.
Arka plan
DOM XSS, uzun yıllardır en yaygın ve tehlikeli web güvenliği açıklarından biri olmuştur.
İki tür siteler arası komut dosyası çalıştırma vardır. Bazı XSS güvenlik açıkları, web sitesini oluşturan HTML kodunu güvenli olmayan bir şekilde oluşturan sunucu tarafı kodundan kaynaklanır. Diğerlerinde ise JavaScript kodu, kullanıcı tarafından kontrol edilen içerikle tehlikeli işlevleri çağırdığı için istemcide temel bir neden vardır.
Sunucu tarafı XSS'yi önlemek için dizeleri birleştirerek HTML oluşturmayın. Bunun yerine güvenli bağlama duyarlı otomatik kaçışlı şablon kitaplıkları ve ek hata azaltma için nonce tabanlı bir içerik güvenlik politikası kullanın.
Tarayıcılar artık Trusted Types kullanarak istemci tarafı DOM tabanlı XSS'yi önlemeye de yardımcı olabilir.
API'ye giriş
Trusted Types, aşağıdaki riskli sink işlevlerini kilitleyerek çalışır. Tarayıcı satıcıları ve web çerçeveleri, güvenlik nedeniyle bu özelliklerin kullanılmasını engellediğinden bazılarını zaten tanıyor olabilirsiniz.
- Komut dosyası işleme:
<script src>
ve<script>
öğelerinin metin içeriğini ayarlama. - Dizeden HTML oluşturma:
- Eklenti içeriğini yürütme:
- Çalışma zamanı JavaScript kodu derlemesi:
eval
setTimeout
setInterval
new Function()
Güvenilir Türler, verileri bu hedef işlevlere geçirmeden önce işlemenizi gerektirir. Yalnızca bir dize kullanmak başarısız olur. Bunun nedeni, tarayıcının verilerin güvenilir olup olmadığını bilmemesidir:
anElement.innerHTML = location.href;
Verilerin güvenli bir şekilde işlendiğini belirtmek için özel bir nesne (güvenilir tür) oluşturun.
anElement.innerHTML = aTrustedHTML;
TrustedHTML
nesnesini kabul eder. Diğer hassas hedefler için de TrustedScript
ve TrustedScriptURL
nesneleri vardır.
Trusted Types, uygulamanızın DOM XSS saldırı yüzeyini önemli ölçüde azaltır. Güvenlik incelemelerini basitleştirir ve kodunuzu derlerken, linting yaparken veya paketlerken yapılan tür tabanlı güvenlik kontrollerini çalışma zamanında tarayıcıda uygulamanıza olanak tanır.
Güvenilir Türler'i kullanma
İçerik Güvenliği Politikası ihlali raporlarına hazırlanma
Açık kaynaklı reporting-api-processor veya go-csp-collector gibi bir rapor toplayıcı dağıtabilir ya da ticari muadillerden birini kullanabilirsiniz. Ayrıca, ReportingObserver kullanarak tarayıcıda özel günlük kaydı ekleyebilir ve ihlal hatalarını ayıklayabilirsiniz:
const observer = new ReportingObserver((reports, observer) => {
for (const report of reports) {
if (report.type !== 'csp-violation' ||
report.body.effectiveDirective !== 'require-trusted-types-for') {
continue;
}
const violation = report.body;
console.log('Trusted Types Violation:', violation);
// ... (rest of your logging and reporting logic)
}
}, { buffered: true });
observer.observe();
veya bir etkinlik işleyici ekleyerek:
document.addEventListener('securitypolicyviolation',
console.error.bind(console));
Yalnızca raporlama için CSP üstbilgisi ekleme
Güvenilir Türler'e taşımak istediğiniz dokümanlara aşağıdaki HTTP yanıt başlığını ekleyin:
Content-Security-Policy-Report-Only: require-trusted-types-for 'script'; report-uri //my-csp-endpoint.example
Artık tüm ihlaller //my-csp-endpoint.example
adresine bildiriliyor ancak web sitesi çalışmaya devam ediyor. Sonraki bölümde //my-csp-endpoint.example
işlevinin nasıl çalıştığı açıklanmaktadır.
Trusted Types ihlallerini belirleme
Artık Güvenilir Türler her ihlal tespit ettiğinde tarayıcı, yapılandırılmış bir report-uri
öğesine rapor gönderir. Örneğin, uygulamanız innerHTML
'ya bir dize ilettiğinde tarayıcı aşağıdaki raporu gönderir:
{
"csp-report": {
"document-uri": "https://my.url.example",
"violated-directive": "require-trusted-types-for",
"disposition": "report",
"blocked-uri": "trusted-types-sink",
"line-number": 39,
"column-number": 12,
"source-file": "https://my.url.example/script.js",
"status-code": 0,
"script-sample": "Element innerHTML <img src=x"
}
}
Bu mesaj, 39. satırdaki https://my.url.example/script.js
içinde innerHTML
işlevinin <img src=x
ile başlayan dizeyle çağrıldığını belirtir. Bu bilgiler, kodun hangi bölümlerinin DOM XSS'ye neden olabileceğini ve değiştirilmesi gerektiğini belirlemenize yardımcı olur.
İhlalleri düzeltme
Trusted Types ihlalini düzeltmek için birkaç seçenek vardır. Sorunlu kodu kaldırabilir, bir kitaplık kullanabilir, güvenilir tür politikası oluşturabilir veya son çare olarak varsayılan bir politika oluşturabilirsiniz.
İhlal eden kodu yeniden yazma
Uygun olmayan kodun artık gerekli olmaması veya ihlallere neden olan işlevler olmadan yeniden yazılabilmesi mümkündür:
el.textContent = ''; const img = document.createElement('img'); img.src = 'xyz.jpg'; el.appendChild(img);
el.innerHTML = '<img src=xyz.jpg>';
Kitaplık kullanma
Bazı kitaplıklar, sink işlevlerine iletebileceğiniz Trusted Types'ı zaten oluşturur. Örneğin, bir HTML snippet'ini temizlemek ve XSS yüklerini kaldırmak için DOMPurify'ı kullanabilirsiniz.
import DOMPurify from 'dompurify';
el.innerHTML = DOMPurify.sanitize(html, {RETURN_TRUSTED_TYPE: true});
DOMPurify Trusted Types'ı destekler
ve tarayıcının ihlal oluşturmaması için TrustedHTML
nesnesine sarılmış temizlenmiş HTML döndürür.
Trusted Type politikası oluşturma
Bazen ihlale neden olan kodu kaldıramazsınız ve değeri temizleyip sizin için Güvenilir Tür oluşturacak bir kitaplık yoktur. Bu gibi durumlarda, Güvenilir Tür nesnesini kendiniz oluşturabilirsiniz.
Öncelikle bir politika oluşturun. Politikalar, girişlerinde belirli güvenlik kurallarını zorunlu kılan Trusted Types fabrikalarıdır:
if (window.trustedTypes && trustedTypes.createPolicy) { // Feature testing
const escapeHTMLPolicy = trustedTypes.createPolicy('myEscapePolicy', {
createHTML: string => string.replace(/\</g, '<')
});
}
Bu kod, myEscapePolicy
adlı bir politika oluşturur. Bu politika, createHTML()
işlevini kullanarak TrustedHTML
nesneleri üretebilir. Tanımlanan kurallar, yeni HTML öğelerinin oluşturulmasını önlemek için <
karakterlerini HTML'den kaçırır.
Politikayı şu şekilde kullanın:
const escaped = escapeHTMLPolicy.createHTML('<img src=x onerror=alert(1)>');
console.log(escaped instanceof TrustedHTML); // true
el.innerHTML = escaped; // '<img src=x onerror=alert(1)>'
Varsayılan politika kullanma
Bazen, örneğin bir CDN'den üçüncü taraf kitaplığı yüklüyorsanız ihlalde bulunan kodu değiştiremezsiniz. Bu durumda varsayılan bir politika kullanın:
if (window.trustedTypes && trustedTypes.createPolicy) { // Feature testing
trustedTypes.createPolicy('default', {
createHTML: (string, sink) => DOMPurify.sanitize(string, {RETURN_TRUSTED_TYPE: true})
});
}
default
adlı politika, yalnızca güvenilir türü kabul eden bir alanda dize kullanıldığında uygulanır.
İçerik Güvenliği Politikası'nı zorunlu kılmaya geçiş
Uygulamanız artık ihlal oluşturmadığında Güvenilir Türler'i zorunlu kılmaya başlayabilirsiniz:
Content-Security-Policy: require-trusted-types-for 'script'; report-uri //my-csp-endpoint.example
Artık web uygulamanız ne kadar karmaşık olursa olsun, DOM XSS güvenlik açığına neden olabilecek tek şey politikalarınızdan birindeki koddur. Politika oluşturmayı sınırlayarak bu durumu daha da güvenli hale getirebilirsiniz.