Güvenilir Türler ile DOM tabanlı siteler arası komut dosyası oluşturma güvenlik açıklarını önleyin

Krzysztof Kotowicz
Krzysztof Kotowicz

Browser Support

  • Chrome: 83.
  • Edge: 83.
  • Firefox: behind a flag.
  • Safari: 26.

Source

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.

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:

Yapılmaması gerekenler:
anElement.innerHTML  = location.href;
Trusted Types etkinleştirildiğinde tarayıcı TypeError hatası verir ve bir dizeyle DOM XSS havuzunun kullanılmasını engeller.

Verilerin güvenli bir şekilde işlendiğini belirtmek için özel bir nesne (güvenilir tür) oluşturun.

Yapılması gerekenler
anElement.innerHTML = aTrustedHTML;
  
Güvenilir Türler etkinleştirildiğinde tarayıcı, HTML snippet'leri bekleyen hedefler için 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:

Yapılması gerekenler
el.textContent = '';
const img = document.createElement('img');
img.src = 'xyz.jpg';
el.appendChild(img);
Yapılmaması gerekenler:
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, '&lt;')
  });
}

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;  // '&lt;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.

Daha fazla bilgi