ถ้าคุณเคยเขียน JavaScript กับ DOM มาก่อน คุณอาจคุ้นเคยกับการใช้ innerHTML เพื่อจัดการกับเนื้อหา HTML ภายในหน้าเว็บ แต่พอเปลี่ยนมาใช้ React คุณอาจสังเกตว่า React ไม่แนะนำให้คุณใช้มัน แล้วทำไมล่ะ? ในบทความนี้ เราจะอธิบายว่าทำไม React ถึงหลีกเลี่ยง innerHTML พร้อมกับแนะนำวิธีเขียนโค้ดที่ปลอดภัยและป้องกัน Cross-Site Scripting (XSS) ได้อย่างมีประสิทธิภาพ
innerHTML คืออะไร? 💡
innerHTML เป็น property ของ DOM ที่ช่วยให้เราสามารถอัปเดตหรือดึงเนื้อหา HTML ของ element ได้โดยตรง เช่น
document.getElementById("content").innerHTML = "<h1>Hello, World!</h1>";
ฟังดูสะดวกใช่ไหม? แต่ปัญหาใหญ่คือ innerHTML เปิดช่องให้โค้ดที่ไม่ปลอดภัย (หรือไม่ตั้งใจ) ถูก inject เข้ามาในหน้าเว็บได้ เช่น
const userInput = "<script>alert('Hacked!');</script>";
document.getElementById("content").innerHTML = userInput;
ผลลัพธ์: หน้าเว็บของคุณอาจโดนโจมตีทันทีจาก Cross-Site Scripting (XSS)!
Cross-Site Scripting (XSS) คืออะไร? 🛡️
XSS (Cross-Site Scripting) เป็นการโจมตีที่แฮกเกอร์ inject โค้ดที่ไม่ปลอดภัย (เช่น <script> หรือโค้ด JavaScript อันตราย) เข้ามาในเว็บเพื่อขโมยข้อมูลหรือทำลายระบบ
ตัวอย่างการโจมตี XSS
- ขโมยคุกกี้: แฮกเกอร์ inject โค้ดเพื่อขโมยข้อมูล session ของผู้ใช้
- เปลี่ยนแปลงหน้าเว็บ: ใส่โค้ดปลอมหลอกผู้ใช้ เช่น ฟอร์มที่ดักข้อมูลส่วนตัว
- เรียกใช้มัลแวร์: ส่งโค้ดที่ดาวน์โหลดมัลแวร์มาติดตั้งในเครื่องผู้ใช้
React กับ dangerouslySetInnerHTML 🤖
ใน React เราไม่สามารถใช้ innerHTML โดยตรง แต่ React มีทางเลือกที่ชื่อว่า dangerouslySetInnerHTML ซึ่งเปิดโอกาสให้คุณแทรก HTML ดิบเข้าไปใน DOM ได้ เช่น
function App() {
const rawHTML = { __html: "<h1>React is awesome!</h1>" };
return <div dangerouslySetInnerHTML={rawHTML}></div>;
}
แล้วทำไมถึง “อันตราย”?
React ตั้งชื่อว่า “dangerously” เพื่อเตือนว่า การใช้งานต้องระวังเป็นพิเศษ เพราะหากคุณส่งข้อมูลที่ไม่ได้ตรวจสอบอย่างดีไปยัง dangerouslySetInnerHTML มันอาจเปิดช่องโหว่ให้โดนโจมตี XSS ได้
การใช้ DOMPurify เพื่อป้องกัน XSS 🧹
ถ้าคุณจำเป็นต้องใช้ dangerouslySetInnerHTML จริง ๆ การตรวจสอบและ “ล้าง” ข้อมูลก่อนแทรกเข้าไปใน DOM เป็นสิ่งที่ขาดไม่ได้
แนะนำ DOMPurify: DOMPurify เป็น library ที่ช่วย “ล้าง” HTML ดิบให้ปลอดภัยจาก XSS
ตัวอย่างการใช้งาน
import DOMPurify from "dompurify";
function App() {
const rawHTML = "<script>alert('Hacked!');</script><h1>Hello, Safe World!</h1>";
const sanitizedHTML = DOMPurify.sanitize(rawHTML); // ล้าง HTML ให้ปลอดภัย
return <div dangerouslySetInnerHTML={{ __html: sanitizedHTML }}></div>;
}
ผลลัพธ์: โค้ดอันตรายจะถูกกำจัดออกไป และเนื้อหา HTML ที่เหลือจะถูกแสดงอย่างปลอดภัย
Best Practices ในการใช้ dangerouslySetInnerHTML 🛠️
หากคุณหลีกเลี่ยงการใช้ dangerouslySetInnerHTML ไม่ได้ นี่คือวิธีปฏิบัติที่ดีที่สุด:
- ตรวจสอบข้อมูลก่อนแทรก: ใช้ library อย่าง DOMPurify
- ใช้ whitelist: อนุญาตเฉพาะ tag และ attribute ที่จำเป็น
- จำกัดข้อมูลจากผู้ใช้: อย่าแทรก HTML ที่มาจาก input โดยตรง
- หลีกเลี่ยงการใช้ถ้าไม่จำเป็น: พยายามใช้ JSX แทน
ตัวอย่างที่ดี
function SafeComponent({ userInput }) {
const sanitizedInput = DOMPurify.sanitize(userInput);
return <div dangerouslySetInnerHTML={{ __html: sanitizedInput }}></div>;
}
ตัวอย่างที่ควรหลีกเลี่ยง
function UnsafeComponent({ userInput }) {
return <div dangerouslySetInnerHTML={{ __html: userInput }}></div>;
}
สรุป React ห่วงใยเรา ❤️
React ไม่อยากให้คุณใช้ innerHTML เพราะมันอาจทำให้แอปพลิเคชันของคุณโดนโจมตี XSS ได้ง่าย การใช้ dangerouslySetInnerHTML ควรทำด้วยความระมัดระวัง และการป้องกัน XSS ด้วย library เช่น DOMPurify จะช่วยให้แอปของคุณปลอดภัยยิ่งขึ้น