ทำไม React ไม่อยากให้เราใช้ innerHTML? 🤔

·
20 พฤศจิกายน 2024
·
Security, Web Development
ทำไม React ไม่อยากให้เราใช้ innerHTML? 🤔

ถ้าคุณเคยเขียน 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) คืออะไร? 🛡️

XSS (Cross-Site Scripting) เป็นการโจมตีที่แฮกเกอร์ inject โค้ดที่ไม่ปลอดภัย (เช่น <script> หรือโค้ด JavaScript อันตราย) เข้ามาในเว็บเพื่อขโมยข้อมูลหรือทำลายระบบ

ตัวอย่างการโจมตี XSS

  1. ขโมยคุกกี้: แฮกเกอร์ inject โค้ดเพื่อขโมยข้อมูล session ของผู้ใช้
  2. เปลี่ยนแปลงหน้าเว็บ: ใส่โค้ดปลอมหลอกผู้ใช้ เช่น ฟอร์มที่ดักข้อมูลส่วนตัว
  3. เรียกใช้มัลแวร์: ส่งโค้ดที่ดาวน์โหลดมัลแวร์มาติดตั้งในเครื่องผู้ใช้

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>;
}

Best Practices ในการใช้ dangerouslySetInnerHTML 🛠️

หากคุณหลีกเลี่ยงการใช้ dangerouslySetInnerHTML ไม่ได้ นี่คือวิธีปฏิบัติที่ดีที่สุด:

  1. ตรวจสอบข้อมูลก่อนแทรก: ใช้ library อย่าง DOMPurify
  2. ใช้ whitelist: อนุญาตเฉพาะ tag และ attribute ที่จำเป็น
  3. จำกัดข้อมูลจากผู้ใช้: อย่าแทรก HTML ที่มาจาก input โดยตรง
  4. หลีกเลี่ยงการใช้ถ้าไม่จำเป็น: พยายามใช้ 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 จะช่วยให้แอปของคุณปลอดภัยยิ่งขึ้น