Mulai Chrome 120, opsi unsanitized
baru tersedia di Papan Klip Asinkron
Compute Engine API. Opsi ini dapat membantu dalam situasi khusus dengan HTML, di mana Anda harus
menempel konten {i>clipboard<i} sesuai dengan
ketika konten disalin.
Artinya, tanpa langkah sanitasi perantara yang biasanya oleh browser—dan
untuk alasan yang baik—ajukan permohonan. Pelajari cara menggunakannya dalam panduan ini.
Saat bekerja dengan API Papan Klip Asinkron, dalam kebanyakan kasus, pengembang tidak perlu mengkhawatirkan integritas konten di papan klip dan dapat mengasumsikan bahwa apa yang mereka tulis ke papan klip (copy) adalah penyimpanan yang sama dengan yang akan mereka dapatkan ketika membaca data dari {i>clipboard<i} (tempel).
Hal ini memang benar untuk teks. Coba tempelkan kode berikut di DevTools
Konsol, lalu segera fokuskan ulang halaman. (setTimeout()
diperlukan
sehingga Anda punya cukup waktu untuk memfokuskan halaman, yang merupakan persyaratan
API Papan Klip.) Seperti yang Anda lihat, inputnya persis sama dengan output.
setTimeout(async () => {
const input = 'Hello';
await navigator.clipboard.writeText(input);
const output = await navigator.clipboard.readText();
console.log(input, output, input === output);
// Logs "Hello Hello true".
}, 3000);
Dengan gambar, akan sedikit berbeda. Untuk mencegah apa yang disebut serangan bom kompresi, browser mengenkode ulang gambar seperti PNG, tetapi gambar input dan outputnya secara visual sama persis, yaitu piksel per piksel.
setTimeout(async () => {
const dataURL =
'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVQYV2NgYAAAAAMAAWgmWQ0AAAAASUVORK5CYII=';
const input = await fetch(dataURL).then((response) => response.blob());
await navigator.clipboard.write([
new ClipboardItem({
[input.type]: input,
}),
]);
const [clipboardItem] = await navigator.clipboard.read();
const output = await clipboardItem.getType(input.type);
console.log(input.size, output.size, input.type === output.type);
// Logs "68 161 true".
}, 3000);
Namun, apa yang terjadi dengan teks HTML? Seperti yang Anda duga, dengan HTML,
situasi yang berbeda. Di sini, browser membersihkan kode HTML untuk mencegah hal
agar tidak terjadi, misalnya dengan menghapus tag <script>
dari HTML
(dan lainnya seperti <meta>
, <head>
, dan <style>
) serta dengan menyisipkan CSS.
Pertimbangkan contoh berikut dan cobalah di Konsol DevTools. Anda akan
perhatikan bahwa {i>output<i} sangat berbeda
dengan inputnya.
setTimeout(async () => {
const input = `<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta name="ProgId" content="Excel.Sheet" />
<meta name="Generator" content="Microsoft Excel 15" />
<style>
body {
font-family: HK Grotesk;
background-color: var(--color-bg);
}
</style>
</head>
<body>
<div>hello</div>
</body>
</html>`;
const inputBlob = new Blob([input], { type: 'text/html' });
await navigator.clipboard.write([
new ClipboardItem({
'text/html': inputBlob,
}),
]);
const [clipboardItem] = await navigator.clipboard.read();
const outputBlob = await clipboardItem.getType('text/html');
const output = await outputBlob.text();
console.log(input, output);
}, 3000);
Sanitasi HTML umumnya adalah hal yang baik. Anda tidak ingin mengekspos diri terhadap masalah keamanan dengan membolehkan HTML yang bermasalah dalam banyak kasus. Ada adalah skenario, di mana pengembang tahu tepat apa yang mereka lakukan dan di mana integritas HTML dalam-dan-{i>output <i}sangat penting untuk fungsi aplikasi. Dalam situasi ini, Anda memiliki dua pilihan:
- Jika Anda mengontrol proses penyalinan dan penempelan, misalnya, jika Anda menyalin dari dalam aplikasi kemudian menempel di dalam aplikasi, Anda harus menggunakan Format kustom web untuk Async Clipboard API. Berhenti membaca di sini dan periksa artikel tertaut.
- Jika Anda hanya mengontrol akhiran penempelan di aplikasi Anda, tetapi tidak ujung penyalinan,
mungkin karena operasi penyalinan terjadi
di aplikasi asli yang tidak mendukung
format kustom web, Anda harus menggunakan opsi
unsanitized
, yang dijelaskan dalam sisa artikel ini.
Sanitasi mencakup hal-hal seperti menghapus tag script
, menyisipkan gaya, dan
memastikan bahwa HTML tersusun dengan baik. Daftar ini tidak komprehensif, dan banyak lagi
langkah-langkah tambahan mungkin
akan ditambahkan di masa mendatang.
Salin dan tempel HTML yang bermasalah
Saat Anda write()
(menyalin) HTML ke papan klip dengan API Papan Klip Asinkron,
browser memastikan bahwa tersusun dengan baik dengan menjalankannya melalui parser DOM
dan membuat serialisasi string HTML yang dihasilkan, tetapi tidak ada sanitasi yang terjadi di
langkah ini. Anda tidak perlu melakukan apa pun. Saat Anda read()
HTML ditempatkan pada
papan klip oleh aplikasi lain, dan aplikasi web Anda ikut serta untuk mendapatkan
konten dengan fidelitas lengkap dan perlu melakukan
sanitasi dalam kode Anda sendiri,
Anda dapat meneruskan objek opsi ke metode read()
dengan properti
unsanitized
dan nilai ['text/html']
. Secara terpisah, tampilannya seperti ini:
navigator.clipboard.read({ unsanitized: ['text/html'] })
. Contoh kode berikut
di bawah ini hampir sama dengan yang ditampilkan sebelumnya, tetapi kali ini dengan unsanitized
sebelumnya. Saat Anda mencobanya di DevTools Console, Anda akan melihat bahwa input dan
output-nya sama.
setTimeout(async () => {
const input = `<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta name="ProgId" content="Excel.Sheet" />
<meta name="Generator" content="Microsoft Excel 15" />
<style>
body {
font-family: HK Grotesk;
background-color: var(--color-bg);
}
</style>
</head>
<body>
<div>hello</div>
</body>
</html>`;
const inputBlob = new Blob([input], { type: 'text/html' });
await navigator.clipboard.write([
new ClipboardItem({
'text/html': inputBlob,
}),
]);
const [clipboardItem] = await navigator.clipboard.read({
unsanitized: ['text/html'],
});
const outputBlob = await clipboardItem.getType('text/html');
const output = await outputBlob.text();
console.log(input, output);
}, 3000);
Dukungan browser dan deteksi fitur
Tidak ada cara langsung untuk memeriksa apakah fitur tersebut didukung, jadi
deteksi didasarkan pada
pengamatan perilaku. Oleh karena itu, contoh berikut
bergantung pada deteksi fakta apakah tag <style>
bertahan, yang
menunjukkan dukungan, atau sedang disisipkan, yang menunjukkan non-dukungan. Perlu diketahui bahwa
agar berfungsi, halaman harus memiliki {i>clipboard<i}
izin akses.
const supportsUnsanitized = async () => {
const input = `<style>p{color:red}</style><p>a`;
const inputBlob = new Blob([input], { type: 'text/html' });
await navigator.clipboard.write([
new ClipboardItem({
'text/html': inputBlob,
}),
]);
const [clipboardItem] = await navigator.clipboard.read({
unsanitized: ['text/html],
});
const outputBlob = await clipboardItem.getType('text/html');
const output = await outputBlob.text();
return /<style>/.test(output);
};
Demo
Untuk melihat cara kerja opsi unsanitized
, lihat
demo di Glitch dan lihat
kode sumber.
Kesimpulan
Seperti yang diuraikan dalam pendahuluan, sebagian besar pengembang tidak perlu khawatir tentang
sanitasi papan klip dan hanya dapat berfungsi dengan opsi sanitasi default
yang dibuat oleh browser. Untuk kasus yang jarang terjadi ketika developer perlu peduli,
Opsi unsanitized
ada.
Link penting
Ucapan terima kasih
Artikel ini diulas oleh Anupam Snigdha dan Rachel Andrew. API ditentukan dan yang diterapkan oleh tim Microsoft Edge.