ใน Chrome 120 มีตัวเลือก unsanitized
ใหม่พร้อมให้ใช้งานในคลิปบอร์ดแบบไม่พร้อมกัน
API ตัวเลือกนี้สามารถให้ความช่วยเหลือในกรณีพิเศษเกี่ยวกับ HTML ซึ่งคุณจำเป็นต้อง
วางเนื้อหาของคลิปบอร์ดที่เหมือนกับตอนที่คัดลอก
กล่าวคือ ไม่ต้องมีขั้นตอนการทำความสะอาดข้อมูลชั่วคราวระหว่างที่เบราว์เซอร์มักดำเนินการ และ
ด้วยเหตุผลที่ดี ให้สมัคร เรียนรู้วิธีใช้งานได้ในคู่มือนี้
เมื่อใช้ Async Clipboard API ในกรณีส่วนใหญ่ นักพัฒนาซอฟต์แวร์ไม่จำเป็นต้องกังวลเกี่ยวกับความสมบูรณ์ของ เนื้อหาในคลิปบอร์ด และอาจเดาได้ว่าเนื้อหาที่เขียนลงใน คลิปบอร์ด (สำเนา) จะได้รับเนื้อหาเดียวกันเมื่ออ่านข้อมูลจากคลิปบอร์ด คลิปบอร์ด (วาง)
ซึ่งแน่นอนว่าต้องเป็นข้อความ ลองวางโค้ดต่อไปนี้ในเครื่องมือสำหรับนักพัฒนาเว็บ
คอนโซลแล้วโฟกัสที่หน้าเว็บอีกครั้งทันที (จำเป็นต้องป้อน setTimeout()
ทำให้คุณมีเวลาพอที่จะโฟกัสที่หน้าเว็บ ซึ่งเป็นข้อกำหนดของโหมดอะซิงโครนัส
API คลิปบอร์ด) คุณจะเห็นว่าอินพุตตรงกับเอาต์พุตทุกประการ
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);
ด้วยรูปภาพ จะแตกต่างไปเล็กน้อย เพื่อป้องกันการเรียก การโจมตีแบบคอมเพรสชันบอมบ์, เบราว์เซอร์ เข้ารหัสรูปภาพ เช่น PNG อีกครั้ง แต่อินพุตและเอาต์พุตรูปภาพเป็นภาพ คือพิกเซลต่อพิกเซล
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);
แต่จะเกิดอะไรขึ้นกับข้อความ HTML ตามที่คุณอาจเดาได้อยู่แล้ว สำหรับ HTML องค์ประกอบ
สถานการณ์ไม่เหมือนกัน ในจุดนี้ เบราว์เซอร์จะล้างโค้ด HTML เพื่อป้องกันข้อผิดพลาด
ไม่ให้อะไรเกิดขึ้น เช่น ตัดแท็ก <script>
ออกจาก HTML
(และอื่นๆ เช่น <meta>
, <head>
และ <style>
) และ CSS แบบอินไลน์
ลองดูตัวอย่างต่อไปนี้และลองใช้ในคอนโซลเครื่องมือสำหรับนักพัฒนาเว็บ คุณจะ
คุณจะสังเกตเห็นว่าเอาต์พุตต่างจากอินพุตอย่างมาก
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);
โดยทั่วไปแล้ว การตรวจสอบความถูกต้องของ HTML เป็นสิ่งที่ดี คุณไม่ต้องการเปิดเผยตัว ปัญหาด้านความปลอดภัยโดยอนุญาตให้มี HTML ที่ไม่ผ่านการตรวจสอบได้ในกรณีส่วนใหญ่ มี แต่เป็นสถานการณ์จำลองที่นักพัฒนาซอฟต์แวร์รู้ว่ากำลังทำอะไรอยู่และ โดยที่ความสมบูรณ์ของ HTML ทั้งในและเอาต์พุตเป็นสิ่งสำคัญสำหรับ ฟังก์ชันการทำงานของแอป ภายใต้สถานการณ์นี้ คุณมี 2 ทางเลือกดังนี้
- ตัวอย่างเช่น ถ้าคุณควบคุมทั้งจุดสิ้นสุดในการคัดลอกและวาง จากภายในแอปเพื่อวางในแอป คุณควรใช้ รูปแบบที่กำหนดเองบนเว็บสำหรับ Async Clipboard API หยุดอ่านที่นี่และตรวจสอบบทความที่ลิงก์
- หากคุณควบคุมเฉพาะจุดสิ้นสุดการวางในแอป แต่ควบคุมจุดสิ้นสุดการคัดลอก
อาจเป็นเพราะการดำเนินการคัดลอกเกิดขึ้นในแอปที่มาพร้อมเครื่องซึ่งไม่รองรับ
รูปแบบที่กำหนดเองแบบเว็บ คุณควรใช้ตัวเลือก
unsanitized
ซึ่งเป็น ซึ่งอธิบายไว้ในส่วนที่เหลือของบทความนี้
การปรับปรุงเนื้อหารวมถึงสิ่งต่อไปนี้ เช่น การนำแท็ก script
ออก รูปแบบอินไลน์ และ
ให้แน่ใจว่า HTML อยู่ในรูปแบบที่ถูกต้อง รายการนี้เป็นแบบไม่ครอบคลุมและอื่นๆ
ในอนาคต
คัดลอกและวาง HTML ที่ไม่ผ่านการตรวจสอบ
เมื่อคุณwrite()
(คัดลอก) HTML ไปยังคลิปบอร์ดด้วย Async Clipboard API
เบราว์เซอร์จะตรวจสอบว่าเบราว์เซอร์มีรูปแบบที่ถูกต้องโดยการเรียกใช้ผ่านโปรแกรมแยกวิเคราะห์ DOM
และการจัดลำดับสตริง HTML ที่ได้มานั้น แต่ไม่มีการทำข้อมูลให้เป็นไปตามนโยบาย
ขั้นตอนนี้ คุณไม่จำเป็นต้องดำเนินการใดๆ เมื่อคุณวาง HTML read()
ใน
คลิปบอร์ดตามแอปพลิเคชันอื่น และเว็บแอปของคุณเลือกใช้
เนื้อหาที่มีความแม่นยำครบถ้วนและจำเป็นต้องดำเนินการทำความสะอาดข้อมูลในโค้ดของคุณเอง
คุณสามารถส่งออบเจ็กต์ตัวเลือกไปยังเมธอด read()
ที่มีพร็อพเพอร์ตี้ได้
unsanitized
และค่า ['text/html']
โดยแยกออกมาให้มีลักษณะดังต่อไปนี้
navigator.clipboard.read({ unsanitized: ['text/html'] })
ตัวอย่างโค้ดต่อไปนี้
ด้านล่างนั้นแทบจะเหมือนกันกับที่แสดงไว้ก่อนหน้านี้ แต่คราวนี้ด้วยunsanitized
ตัวเลือก เมื่อลองใช้ในคอนโซลเครื่องมือสำหรับนักพัฒนาเว็บ คุณจะเห็นว่าอินพุตและ
เอาต์พุตจะเหมือนกัน
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);
การรองรับเบราว์เซอร์และการตรวจหาฟีเจอร์
เนื่องจากยังไม่มีวิธีโดยตรงในการตรวจสอบว่า ฟีเจอร์นี้ได้รับการสนับสนุนหรือไม่ ดังนั้น
จะขึ้นอยู่กับการสังเกตพฤติกรรม ดังนั้นตัวอย่างต่อไปนี้
อาศัยการตรวจจับข้อเท็จจริงที่ว่าแท็ก <style>
อยู่รอดหรือไม่
บ่งชี้ถึงการรองรับ หรืออยู่ระหว่างในบรรทัด ซึ่งบ่งชี้ว่าไม่สนับสนุน โปรดทราบว่า
เพื่อให้สิ่งนี้ทำงาน หน้าเว็บต้องได้รับคลิปบอร์ดอยู่แล้ว
สิทธิ์
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);
};
สาธิต
หากต้องการดูตัวเลือก unsanitized
ในการใช้งานจริง โปรดดู
การสาธิตเกี่ยวกับ Glitch และดู
ซอร์สโค้ด
บทสรุป
ตามที่ได้กล่าวไว้ในบทนำ นักพัฒนาแอปส่วนใหญ่ไม่จำเป็นต้องกังวลเกี่ยวกับ
การทำความสะอาดคลิปบอร์ดและสามารถทำงานกับตัวเลือกการล้างข้อมูลเริ่มต้นได้
สร้างโดยเบราว์เซอร์ ในกรณีที่พบไม่บ่อยนักที่นักพัฒนาแอปต้องระมัดระวัง
มีตัวเลือก unsanitized
รายการ
ลิงก์ที่มีประโยชน์
กิตติกรรมประกาศ
บทความนี้ได้รับการตรวจสอบโดย Anupam Snigdha และ Rachel Andrew ระบุ API และ ที่ทีม Microsoft Edge นำมาใช้