Trusted Types adalah fitur keamanan yang membantu mencegah Pembuatan Skrip Lintas Situs berbasis DOM (DOM XSS) dengan mewajibkan data yang diteruskan ke API browser "berbahaya" (dikenal sebagai sink) dikonversi terlebih dahulu menjadi jenis tertentu, seperti TrustedHTML.
Secara default, banyak DOM API (seperti innerHTML atau document.write) menerima string mentah. Jika string berisi skrip berbahaya dari sumber yang tidak tepercaya, skrip tersebut dapat dieksekusi. Trusted Types mengubah perilaku ini: setelah diaktifkan melalui CSP, sink ini hanya akan menerima objek TrustedHTML yang dibuat oleh kebijakan yang diizinkan.
Detail Penerapan Penting
Untuk menggunakan Trusted Types, ikuti empat langkah utama:
- Tentukan kebijakan keamanan yang menentukan cara membersihkan atau mengubah string.
- Gunakan kebijakan tersebut untuk membuat objek Trusted Type dari string mentah.
- Gunakan objek Jenis Tepercaya saat menulis ke sink DOM.
- Terapkan Jenis Tepercaya menggunakan Kebijakan Keamanan Konten (CSP).
1. Membuat Kebijakan
Kebijakan adalah serangkaian aturan untuk membersihkan konten. Anda membuatnya menggunakan trustedTypes.createPolicy(), biasanya mendelegasikan ke library pembersih seperti DOMPurify atau aturan escape HTML aplikasi Anda:
import DOMPurify from 'dompurify';
const myPolicy = trustedTypes.createPolicy('sanitize-html', {
createHTML: (input) =>
// Return a sanitized string; createPolicy() wraps it in a TrustedHTML object.
// Example using DOMPurify:
DOMPurify.sanitize(input, { RETURN_TRUSTED_TYPE: false }),
});
// Example using HTML escaping (for environments without third-party sanitizers):
const escapePolicy = trustedTypes.createPolicy('escape-html', {
createHTML: (input) =>
String(input)
.replaceAll('&', '&')
.replaceAll('<', '<')
.replaceAll('>', '>')
.replaceAll('"', '"')
.replaceAll("'", '''),
});
2. Menggunakan Kebijakan
Alih-alih meneruskan string langsung ke sink, Anda memanggil metode pembuatan kebijakan.
const untrustedInput = '<p>Hello, <strong>world</strong>!</p><img src="x" onerror="alert(1)">';
// In an enforced environment, this would throw a TypeError:
// element.innerHTML = untrustedInput;
// This returns a TrustedHTML object with unsafe elements and attributes removed:
const cleanHTML = myPolicy.createHTML(untrustedInput);
// Result: "<p>Hello, <strong>world</strong>!</p><img src=\"x\">"
3. Mentransisikan sink untuk menggunakan Trusted Types
Perbarui setiap instance tempat Anda menulis ke sink untuk mengonversinya terlebih dahulu menjadi objek Trusted Type. Untuk membantu menemukan tempat kode perlu diperbarui, Anda dapat menentukan kebijakan default sementara yang mencatat log saat sink ditulis dengan string, bukan TrustedType.
trustedTypes.createPolicy("default", {
createHTML(value) {
console.warn("String passed instead of Trusted Type.");
return DOMPurify.sanitize(value, { RETURN_TRUSTED_TYPE: false });
},
});
Sink umum yang mendukung Trusted Types meliputi:
- HTML:
element.innerHTML,element.outerHTML,document.write(),element.setHTMLUnsafe(),Document.parseHTMLUnsafe() - Skrip: Konten teks
<script>,eval() - ScriptURL:
<script src>,Worker(),SharedWorker()
// Assign the TrustedHTML object.
element.innerHTML = cleanHTML;
Perhatikan bahwa metode sanitasi HTML "aman" (element.setHTML() dan Document.parseHTML(), yang dibahas dalam Melakukan Sanitasi HTML yang Tidak Tepercaya), tidak memerlukan kebijakan Jenis Tepercaya, karena metode tersebut selalu melakukan sanitasi terhadap potensi serangan XSS secara native.
4. Menerapkan Trusted Types dengan CSP
Jenis Tepercaya harus diluncurkan secara bertahap untuk menghindari kerusakan pada aplikasi Anda. Meskipun penerapan penuh memberikan perlindungan terkuat, hal ini berisiko merusak situs jika setiap penulisan sink belum dimigrasikan.
Prasyarat
- Kerja sama framework: Jika framework aplikasi Anda (atau library pihak ketiga mana pun yang menulis ke sink DOM) tidak menghasilkan nilai
TrustedHTMLatauTrustedScript, Anda tidak dapat menerapkan Jenis Tepercaya tanpa merusak kode tersebut. Audit dukungan framework sebelum memulai peluncuran. - Refaktorisasi sink: Pastikan Anda telah mengidentifikasi dan merefaktorisasi sink berbahaya untuk menggunakan kebijakan Trusted Types Anda.
Strategi Peluncuran
Hanya Laporan: Pertama, luncurkan menggunakan header
Content-Security-Policy-Report-Only. Tindakan ini akan mencatat pelanggaran ke endpoint pelaporan Anda tanpa benar-benar memblokir penulisan.Content-Security-Policy-Report-Only: require-trusted-types-for 'script';Penegakan: Setelah Anda mengintegrasikan kebijakan dan laporan pelanggaran turun menjadi nol, beralihlah ke penegakan penuh.
Content-Security-Policy: require-trusted-types-for 'script';
Anda juga dapat membatasi kebijakan yang diizinkan untuk dibuat (cantumkan nama kebijakan Anda seperti sanitize-html atau escape-html, sertakan dompurify jika kebijakan Anda didelegasikan ke DOMPurify.sanitize()—yang secara internal membuat kebijakan dompurify—dan sertakan default jika Anda mendaftarkan kebijakan default selama migrasi):
Content-Security-Policy: require-trusted-types-for 'script'; trusted-types sanitize-html escape-html dompurify;
Dengan CSP ini, setiap penulisan ke sink yang tidak menggunakan Trusted Types akan menampilkan error. Selain itu, mencoba membuat kebijakan Jenis Tepercaya dengan nama yang tidak tercantum di trusted-types akan menampilkan error.
Anda juga dapat menetapkan CSP ini sebagai tag <meta> di <head> dokumen, meskipun hal ini berpotensi kurang aman.
<!-- First child of `<head>`, as earlier tags will not enforce this CSP. -->
<meta
http-equiv="Content-Security-Policy"
content="require-trusted-types-for 'script'; trusted-types sanitize-html escape-html dompurify;"
/>
Strategi penggantian
Untuk browser yang belum mendukung Jenis Tepercaya, Anda dapat menggunakan "tinyfill" minimal untuk memastikan kode Anda tidak rusak sekaligus tetap menyediakan sanitasi.
if (!window.trustedTypes) {
window.trustedTypes = {
createPolicy: (name, rules) => rules,
};
}
Dengan demikian, Anda dapat menulis kode menggunakan pola Trusted Types sekarang. Browser yang mendukung akan menerapkan jenis, sedangkan browser lama akan tetap menjalankan logika pembersihan Anda melalui kebijakan tiruan.
Jika browser tidak mendukung Jenis Tepercaya, browser hanya akan memperlakukan objek TrustedHTML sebagai string (jika menggunakan tinyfill) atau tidak akan memiliki pemeriksaan penerapan di tingkat sink.