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

Krzysztof Kotowicz
Krzysztof Kotowicz

Tarayıcı desteği

  • Chrome: 83.
  • Edge: 83.
  • Firefox: Desteklenmez.
  • Safari: Desteklenmez.

Kaynak

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 yönlendirme URL'si) gelen veriler eval() gibi bir işlev veya .innerHTML gibi rastgele JavaScript kodunu çalıştırabilen bir özellik ayarlayıcı olan bir alıcıya ulaştığında gerçekleşir.

DOM XSS, en yaygın web güvenlik açıklarından biridir ve geliştirici ekiplerinin bu açıkları uygulamalarına yanlışlıkla dahil etmesi yaygındır. Güvenilir Türleri, tehlikeli web API işlevlerini varsayılan olarak güvenli hale getirerek uygulamaları DOM XSS güvenlik açıklarından uzak tutmak, yazmak ve güvenlik incelemesi yapmak için gereken araçları sunar. 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üvenlik açıklarından biri olmuştur.

Siteler arası komut dosyası çalıştırma işleminin iki türü 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ğerlerinin temel nedeni, JavaScript kodunun kullanıcı tarafından kontrol edilen içerikle tehlikeli işlevler çağırması nedeniyle istemcidedir.

Sunucu tarafı XSS'yi önlemek için dizeleri birleştirerek HTML oluşturmayın. Daha fazla hata azaltma için bunun yerine güvenli bağlama dayalı otomatik kaçış karakteri ekleme şablon kitaplıklarını ve tek seferlik anahtara dayalı İçerik Güvenliği Politikası'nı kullanın.

Artık tarayıcılar, Güvenilir Türleri kullanarak istemci taraflı DOM tabanlı XSS'yi önlemeye de yardımcı olabilir.

API'ye giriş

Güvenilir Türleri, aşağıdaki riskli akış işlevlerini kilitleyerek çalışır. Tarayıcı tedarikçileri ve web çerçeveleri, güvenlik nedeniyle sizi bu özellikleri kullanmaktan zaten uzak tuttuğundan bunların bazılarını zaten biliyor olabilirsiniz.

Güvenilir Türlerde, verileri bu akış işlevlerine aktarmadan önce işleme almanız gerekir. Tarayıcı, verilerin güvenilir olup olmadığını bilmediği için yalnızca bir dize kullanmak başarısız olur:

Yapılmaması gerekenler:
anElement.innerHTML  = location.href;
Trusted Types etkinleştirildiğinde tarayıcı bir TypeError atar ve bir dizeyle DOM XSS alıcının 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 alıcılar için bir TrustedHTML nesnesini kabul eder. Hassas olmayan diğer lavabolar için TrustedScript ve TrustedScriptURL nesneleri de vardır.

Güvenilir Türleri, uygulamanızın DOM XSS saldırıya açık alanını önemli ölçüde azaltır. Güvenlik incelemelerini basitleştirir ve kodunuzu derleme, linting veya çalışma zamanında paketleme sırasında yapılan tür tabanlı güvenlik kontrollerini tarayıcıda zorunlu kılmanıza olanak tanır.

Güvenilir Türleri kullanma

İçerik Güvenliği Politikası ihlali raporlarına hazırlanma

Açık kaynak reporting-api-processor veya go-csp-collector gibi bir rapor toplayıcı dağıtabilir ya da ticari eşdeğerlerinden birini kullanabilirsiniz. Ayrıca, ReportingObserver kullanarak tarayıcıda özel günlük kaydı ekleyebilir ve ihlalleri hata 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ürlere taşımak istediğiniz dokümanlara aşağıdaki HTTP Yanıt üstbilgisini ekleyin:

Content-Security-Policy-Report-Only: require-trusted-types-for 'script'; report-uri //my-csp-endpoint.example

Tüm ihlaller //my-csp-endpoint.example'e bildirildi ancak web sitesi çalışmaya devam ediyor. //my-csp-endpoint.example'ün işleyiş şekli sonraki bölümde açıklanmıştır.

Trusted Types ihlallerini belirleme

Bundan sonra, Güvenilir Türler bir ihlal her tespit ettiğinde tarayıcı, yapılandırılmış bir report-uri'e rapor gönderir. Örneğin, uygulamanız innerHTML adresine bir dize iletirse 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, 39. satırdaki https://my.url.example/script.js içinde innerHTML'ın <img src=x ile başlayan dizeyle çağrıldığını belirtir. Bu bilgiler, DOM XSS'ye neden olabilecek ve değiştirilmesi gereken kod bölümlerinin daraltılmasına yardımcı olacaktır.

İhlalleri düzeltme

Güvenilir Tür ihlallerini düzeltmek için birkaç seçenek vardır. Sorunlu kodu kaldırabilir, kitaplık kullanabilir, Güvenilir Tür politikası oluşturabilir veya son çare olarak varsayılan politika oluşturabilirsiniz.

Sorunlu kodu yeniden yazma

Uygun olmayan koda artık ihtiyaç duyulmuyor olabilir veya ihlallere neden olan işlevler olmadan yeniden yazılabilir:

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, aktarma işlevlerine iletebileceğiniz Güvenilir Türleri zaten oluşturur. Örneğin, bir HTML snippet'ini temizlemek ve XSS yüklerini kaldırmak için DOMPurify'i kullanabilirsiniz.

import DOMPurify from 'dompurify';
el.innerHTML = DOMPurify.sanitize(html, {RETURN_TRUSTED_TYPE: true});

DOMPurify, güvenilir türleri destekler ve tarayıcının ihlal oluşturmaması için temizlenmiş HTML'yi bir TrustedHTML nesnesine sarmalayarak döndürür.

Güvenilir Tür politikası oluşturma

Bazen ihlal oluşturan 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 nesnesi kendiniz oluşturabilirsiniz.

Öncelikle bir politika oluşturun. Politikalar, girişlerinde belirli güvenlik kurallarını uygulayan 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, createHTML() işlevini kullanarak TrustedHTML nesneleri oluşturabilen myEscapePolicy adlı bir politika oluşturur. Tanımlanan kurallar, yeni HTML öğelerinin oluşturulmasını önlemek için < karakterlerini HTML'de kaçar.

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 bir politika kullanma

Bazen, soruna neden olan kodu değiştiremezsiniz. Örneğin, bir CDN'den üçüncü taraf kitaplığı yüklüyorsanız. 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 alıçta dize kullanıldığı her yerde kullanılır.

İçerik Güvenliği Politikası'nı uygulamaya geçme

Uygulamanız artık ihlal oluşturmadığında Güvenilir Türleri uygulamaya koyabilirsiniz:

Content-Security-Policy: require-trusted-types-for 'script'; report-uri //my-csp-endpoint.example

Web uygulamanız ne kadar karmaşık olursa olsun DOM XSS güvenlik açığı oluşturabilecek tek şey politikalarınızdan birindeki koddur. Politika oluşturmayı sınırlandırarak bu açığı daha da azaltabilirsiniz.

Daha fazla bilgi