DOM XSS Zafiyetinden Korunmak - Trusted Types

document.write("Merhabalar");

DOM API ile karmaşık mimarilerde güvenli olarak kod geliştirmek gerçekten zorlu bir süreçtir. Google mühendisleri JS kodunuzu bu tarz ataklara karşı sıkılaştırmak için "Trusted-Types" adında bir yapı ortaya çıkardı. Bu şekilde DOMXSS zafiyetinin büyük ölçüde önüne geçebileceklerini düşünüyorlar.

Temelde, politika oluşturarak kodunuza uygulayabileceğiniz bir yapı. Oluşturulan bu politikalar kullanılmadığı takdirde kod çalışmamaya zorlanabilmekte. Ayrıca kendi sanitize fonsiyonunuzu projenize dahil edebildiğiniz gibi DOMPurify, CSP(Content Security Policy) gibi mekanizmaları da kullanabiliyorsunuz.

Nasıl çalıştığını anlamak adına basit bir uygulama yapalım. İlk olarak "unsafe" adında bir politika oluşturuyoruz.

<script src="https://wicg.github.io/trusted-types/dist/es5/trustedtypes.build.js"></script>
<script>
//Deneme amaçlıdır. Projelerinizde bu şekilde kullanmayın.
var policy = TrustedTypes.createPolicy('unsafe', {
    'createHTML': function(unsafe) {
        return unsafe;
    }
});

document.getElementById('unsafe').innerHTML = policy.createHTML('<b>trusted input</b>');    
</script>       

"var policy = TrustedTypes.createPolicy('unsafe'...)" TrustedTypes kullanarak unsafe adında bir politika yaratıp policy değişkenine atıyoruz. Daha sonra TrustedHTML yapısını çağırmak için CreateHTML methodunu oluşturuyoruz.

Bu kısma sanitize fonksiyonumuzu koymamız gerekiyor. Tabi şu an sadece gelen veriye güvendiğimiz için olduğu gibi return ediyoruz. Bildiğiniz gibi Dom-XSS yapısı source ve sink alanlarından oluşuyor. Yani oluşturmuş olduğumuz politikayı CreateHTML(SOURCE) olarak çağırıyoruz ve DOM-XSS için SINK alanı olan innerHTML ile ekrana yazıyoruz. Sonuç olarak ekrana "trusted input" yazacağız. Şimdi innerHTML sink alanına zararlı bir kod enjekte etmeye çalışalım.

<script>
var policy = TrustedTypes.createPolicy('unsafe', {
    'createHTML': function(unsafe) {
        return unsafe;
    }
});

document.getElementById('unsafe').innerHTML = policy.createHTML('<b>trusted input</b>');            
document.getElementById('unsafe').innerHTML = "Zararlı kod buraya gelecek.";
</script>

innerHTML sink alanına politika dışında bir kod enjekte etmeye çalıştığımızda konsola bakarsanız eğer TypeError hatası aldığınızı göreceksiniz. Başka bir örnek yapalım ve kendi sanitize fonksiyonumuzu uygulayalım.

<script>
//Deneme amaçlıdır. Projelerinizde bu şekilde kullanmayın.
var sanitizer = TrustedTypes.createPolicy(my-policy, {
    'createHTML': function(dirty) {
        return dirty.replace(/</g, '&lt;');
}});

document.getElementById('sanitized-via-policy').innerHTML = sanitizer.createHTML(unescape(location.hash));
</script>

Burada location.hash kaynağını kullanıcıdan alıyoruz ve sanitizer fonksiyonundan geçiriyoruz ve zararlı kod replace edilmiş oluyor. Ayrıca DOMpurify ve CSP gibi yapıları da işin içine katabiliyorsunuz.

<script src="https://cdn.jsdelivr.net/gh/koto/[email protected]/dist/purify.js"></script>
<script src="https://wicg.github.io/trusted-types/dist/es5/trustedtypes.build.js"></script>

<script>
//Deneme amaçlıdır. Projelerinizde bu şekilde kullanmayın.
var sanitizer = TrustedTypes.createPolicy('DOMPurify', {
    'createHTML': function(dirty) {
        return DOMPurify.sanitize(dirty);
}});

document.getElementById('sanitized-via-policy').innerHTML = sanitizer.createHTML(unescape(location.hash));
</script>   
//Eğer CSP kullanırken politikaları bu şekilde yazmazsanız çalışmayacaktır. 
<meta http-equiv="Content-Security-Policy" content="trusted-types my-policy">
<script src="https://cdn.jsdelivr.net/gh/koto/[email protected]/dist/purify.js"></script>
<script src="https://wicg.github.io/trusted-types/dist/es5/trustedtypes.build.js"></script>
<script>
//Deneme amaçlıdır. Projelerinizde bu şekilde kullanmayın.
var sanitizer = TrustedTypes.createPolicy(my-policy, {
    'createHTML': function(dirty) {
        return dirty.replace(/</g, '&lt;');
}});

document.getElementById('sanitized-via-policy').innerHTML = sanitizer.createHTML(unescape(location.hash));
</script>

Görüldüğü gibi politikamıza sırasıyla DOMPurify ve CSP mekanızmalarını dahil ettik.

Bu projenin çok farklı kullanımları olabilir. Ben sadece bir kısmına değindim. Aşağıdaki bağlantıdan projenini Github reposuna erişim sağlayabilir ve katkıda bulunabilirsiniz.

https://github.com/WICG/trusted-types

EOF