กลับไปหน้าบทความ
#CSP#XSS#Web Security#DevOps#Security Header

ใช้ CSP ปิดความเสี่ยง XSS แบบค่อยเป็นค่อยไป โดยไม่ต้องรื้อโค้ดทั้งเว็บ

Content Security Policy (CSP) คือแนวทางสำคัญในการลดความเสี่ยงจาก XSS ได้อย่างรวดเร็ว แม้ระบบจะมีโค้ดเก่า ไลบรารีจำนวนมาก หรือยังไม่พร้อมรีแฟกเตอร์ทั้งเว็บในทันที

16 กุมภาพันธ์ 2569อ่านประมาณ 2 นาที

แชร์บทความ

ใช้ CSP ปิดความเสี่ยง XSS แบบค่อยเป็นค่อยไป โดยไม่ต้องรื้อโค้ดทั้งเว็บ

ใช้ CSP ปิดความเสี่ยง XSS แบบค่อยเป็นค่อยไป โดยไม่ต้องรื้อโค้ดทั้งเว็บ

หลายองค์กรที่พัฒนาเว็บไซต์มาอย่างต่อเนื่องมักต้องเผชิญปัญหาคล้ายกัน คือระบบเติบโตเร็ว มีโค้ดเก่าสะสม ใช้ไลบรารีหลายตัว และเมื่อถึงวันที่มีการสแกนความปลอดภัย ก็อาจพบช่องโหว่ XSS โดยไม่ทันตั้งตัว

ในสถานการณ์ที่ยังไม่สามารถแก้โค้ดทั้งระบบได้ทันที เครื่องมือที่ช่วย “คุมความเสี่ยงได้ก่อน” คือ Content Security Policy (CSP) ซึ่งทำหน้าที่กำหนดกติกาให้เบราว์เซอร์รู้ว่าอะไรควรถูกโหลดและอะไรควรถูกรันได้บ้าง

CSP คืออะไร และช่วยลดความเสี่ยง XSS ได้อย่างไร

XSS มักเกิดขึ้นเมื่อผู้โจมตีสามารถทำให้เบราว์เซอร์รันสคริปต์ที่แอปพลิเคชันไม่ได้ตั้งใจให้รันได้สำเร็จ ไม่ว่าจะผ่านช่องทางการฉีดโค้ดลงใน HTML, พารามิเตอร์ หรือข้อมูลที่แสดงผลกลับไปยังหน้าเว็บ

CSP เข้ามาช่วยโดยกำหนดข้อจำกัดอย่างชัดเจน เช่น อนุญาตให้โหลดสคริปต์ได้จากแหล่งใดบ้าง หรือห้ามใช้รูปแบบการรันบางประเภทอย่างไร ผลคือแม้สคริปต์อันตรายจะหลุดเข้าไปอยู่ในหน้าเว็บได้ แต่ก็อาจไม่สามารถทำงานได้หากไม่ผ่านนโยบายที่กำหนดไว้

กล่าวได้ว่า CSP เปรียบเสมือน “ไฟร์วอลล์ฝั่งเบราว์เซอร์” ที่ช่วยลดโอกาสการรันโค้ดไม่พึงประสงค์ได้อย่างมีประสิทธิภาพ

วิธีเริ่มต้นที่ปลอดภัย: ใช้ Report-Only ก่อน

แนวทางที่แนะนำมากที่สุดคือเริ่มจากโหมด Content-Security-Policy-Report-Only ก่อน เพราะจะยังไม่บล็อกการทำงานจริงของเว็บ แต่จะรายงานให้ทราบว่าเว็บไซต์กำลังพยายามโหลดทรัพยากรหรือรันสคริปต์จากที่ใดบ้าง

ข้อดีของวิธีนี้คือ

  • มองเห็นภาพรวมการพึ่งพาโดเมนภายนอก
  • รู้ว่ามี inline script อยู่มากน้อยเพียงใด
  • ลดความเสี่ยงที่ผู้ใช้จะเจอเว็บพังจากการเปิดใช้ policy เร็วเกินไป
  • ช่วยเก็บข้อมูลจริงจากการใช้งานก่อนบังคับใช้แบบเต็มรูปแบบ

องค์กรจำนวนมากนิยมเปิดโหมดนี้ไว้ประมาณ 1-2 สัปดาห์ เพื่อรวบรวมข้อมูลก่อนออกแบบ allowlist ที่เหมาะสม

ตัวอย่าง Policy เริ่มต้นที่เน้นความปลอดภัย

ตัวอย่างนโยบายพื้นฐานที่นิยมใช้เป็นจุดตั้งต้น ได้แก่

default-src 'self';
script-src 'self';
object-src 'none';
base-uri 'self';
frame-ancestors 'none';

แต่ละบรรทัดมีประโยชน์ดังนี้

  • default-src 'self' กำหนดค่าเริ่มต้นให้โหลดทรัพยากรจากโดเมนเดียวกับเว็บไซต์
  • script-src 'self' อนุญาตให้รันสคริปต์จากแหล่งที่เชื่อถือได้เท่านั้น ช่วยลดโอกาสที่สคริปต์จากโดเมนแปลกปลอมจะทำงาน
  • object-src 'none' ปิดการใช้งานปลั๊กอินเก่า เช่น Flash หรือ object/embed ที่มักเป็นแหล่งปัญหาด้านความปลอดภัย
  • base-uri 'self' ป้องกันการแก้ไข base tag เพื่อเปลี่ยนเส้นทางการอ้างอิงลิงก์หรือสคริปต์ไปยังโดเมนอื่น
  • frame-ancestors 'none' ป้องกันไม่ให้เว็บไซต์ถูกฝังใน iframe ซึ่งช่วยลดความเสี่ยงจาก clickjacking

หลักคิดสำคัญคือ เริ่มให้เข้มก่อน แล้วค่อยผ่อนเฉพาะส่วนที่จำเป็น แทนที่จะเปิดกว้างแล้วค่อยตามปิดทีหลัง

เทคนิคสำคัญ: ลดการพึ่งพา inline script ด้วย nonce

หนึ่งในเหตุผลที่หลายเว็บเปิดใช้ CSP แล้วเกิดปัญหา คือระบบเดิมมี inline script จำนวนมาก หากบล็อกทั้งหมดทันที หน้าเว็บอาจทำงานผิดพลาด

แนวทางที่ใช้งานได้จริงคือการใช้ nonce ซึ่งเป็นค่าสุ่มเฉพาะต่อ request โดยมีขั้นตอนหลักดังนี้

  1. สร้างค่า nonce แบบสุ่มที่คาดเดาได้ยากในทุก request
  2. ใส่ค่า nonce นี้ลงในแท็ก <script> ที่ต้องการอนุญาตเท่านั้น
  3. กำหนด policy ให้ยอมรับเฉพาะสคริปต์ที่มี 'nonce-...'

ผลลัพธ์คือ สคริปต์ที่ผู้โจมตีฉีดเข้ามาใหม่มักจะไม่มี nonce ที่ถูกต้อง จึงไม่สามารถรันได้ แม้อยู่ใน HTML เดียวกันก็ตาม

วิธีนี้เหมาะมากสำหรับการเปลี่ยนผ่านจากระบบเก่าที่พึ่งพา inline script ไปสู่รูปแบบที่ปลอดภัยกว่า โดยไม่ต้องแก้ทุกอย่างพร้อมกันในครั้งเดียว

strict-dynamic กับกรณีที่มีการโหลดสคริปต์แบบต่อเนื่อง

สำหรับบางระบบที่ใช้ script loader หรือ tag manager อาจมีการโหลดสคริปต์แบบ chain ต่อกันหลายชั้น ในกรณีนี้สามารถพิจารณาใช้ strict-dynamic เพื่อให้สคริปต์ที่ได้รับความเชื่อถือแล้วสามารถโหลดสคริปต์ลูกต่อได้อย่างปลอดภัยมากขึ้น

อย่างไรก็ตาม ฟีเจอร์นี้ควรถูกทดสอบอย่างละเอียดก่อนใช้งานจริง เพราะพฤติกรรมของแต่ละระบบอาจแตกต่างกัน และการตั้งค่าที่ไม่เหมาะสมอาจทำให้ policy ซับซ้อนเกินจำเป็น

สิ่งที่ CSP ช่วยได้ทันที

แม้ยังไม่ได้แก้โค้ดทุกจุด CSP ก็ช่วยลดความเสี่ยงได้ในหลายด้าน เช่น

  1. บล็อกการโหลดสคริปต์จากโดเมนที่ไม่ได้รับอนุญาต
  2. บล็อก inline script ที่ถูกฉีดเข้ามาแบบไม่พึงประสงค์
  3. จำกัดผลกระทบของช่องโหว่ที่ยังไม่มีเวลาแก้ไขทันที

ดังนั้น CSP จึงเหมาะอย่างยิ่งกับระบบที่มีทั้ง legacy code, SPA, และการพึ่งพา CDN หลายเจ้า เพราะช่วย “ซื้อเวลา” ให้ทีมค่อย ๆ ปรับปรุงโค้ดอย่างเป็นระบบ

กับดักที่พบบ่อยในการใช้งาน CSP

แม้ CSP จะมีประโยชน์มาก แต่ก็มีข้อผิดพลาดที่พบบ่อยเช่นกัน

  • ใช้ unsafe-inline เพื่อให้เว็บผ่านง่าย ๆ วิธีนี้ทำให้การป้องกัน XSS อ่อนลงมากจนแทบเสียประโยชน์หลักของ CSP
  • มี CDN หรือ third-party หลายรายเกินไป หากไม่จัด allowlist ให้ชัดเจน policy จะยาวและดูแลยาก
  • รายงานจาก Report-Only มีจำนวนมาก หากไม่จัดหมวดหมู่ log ให้ดี ทีมงานอาจวิเคราะห์ต่อได้ยาก

การใช้งาน CSP ให้ได้ผลจึงไม่ใช่แค่การเพิ่ม header แต่ต้องมีการติดตาม วิเคราะห์ และปรับแต่งอย่างต่อเนื่อง

วิธีไล่ปรับแบบมืออาชีพ

แนวทางที่ทีมเทคนิคจำนวนมากใช้มีดังนี้

  1. เปิด Report-Only ชั่วคราวเพื่อเก็บข้อมูลจริงจากผู้ใช้
  2. สร้าง allowlist เฉพาะโดเมนที่จำเป็นจริง
  3. แยก policy ตามความสำคัญของหน้า เช่น หน้า login หรือ admin ควรเข้มกว่าหน้าทั่วไป
  4. ส่ง CSP report เข้า log กลาง หรือระบบ SIEM เพื่อวิเคราะห์เหตุการณ์ได้สะดวกขึ้น

แนวทางนี้ช่วยให้การบังคับใช้นโยบายเป็นไปอย่างค่อยเป็นค่อยไป ลดผลกระทบต่อผู้ใช้ และเพิ่มความมั่นใจในการ deploy จริง

ใช้ CSP โดยไม่ต้องแก้โค้ดทั้งเว็บได้อย่างไร

ข้อดีอีกอย่างของ CSP คือสามารถกำหนดผ่านชั้นโครงสร้างพื้นฐานได้ เช่น

  • Reverse proxy
  • Load balancer
  • CDN edge
  • Web server เช่น Nginx
  • ผู้ให้บริการอย่าง Cloudflare หรือ Akamai

นั่นหมายความว่าในหลายกรณี ทีม DevOps หรือ Platform สามารถเพิ่ม response header ได้โดยไม่ต้องเข้าไปแก้แอปพลิเคชันหลักโดยตรง ทำให้เริ่มควบคุมความเสี่ยงได้เร็วกว่าแนวทางที่ต้องรีแฟกเตอร์ระบบทั้งหมด

Security Header ที่ควรพิจารณาใช้ร่วมกัน

นอกจาก CSP แล้ว ยังมี header อื่นที่มักใช้ร่วมกันเพื่อเสริมความปลอดภัย ได้แก่

  • X-Content-Type-Options: nosniff ลดความเสี่ยงจากการตีความชนิดไฟล์ผิดประเภท
  • Referrer-Policy: strict-origin-when-cross-origin ควบคุมข้อมูล referrer ที่ถูกส่งออกไป
  • Permissions-Policy จำกัดการเข้าถึง API หรือความสามารถของเบราว์เซอร์ที่ไม่จำเป็น

การตั้งค่าเหล่านี้ร่วมกันจะช่วยยกระดับความปลอดภัยของเว็บได้อย่างรอบด้านมากขึ้น

สรุป

CSP เป็นเครื่องมือสำคัญที่ช่วยลดความเสี่ยงจาก XSS ได้อย่างรวดเร็ว โดยเฉพาะในระบบที่ยังมีโค้ดเก่าจำนวนมากและไม่สามารถแก้ทั้งหมดได้ทันที แนวทางที่ดีที่สุดคือเริ่มจาก Report-Only เพื่อเก็บข้อมูลก่อน จากนั้นค่อยปรับ allowlist และเพิ่มความเข้มงวดทีละขั้น

หากต้องรับมือกับ inline script จำนวนมาก ควรใช้ nonce แทนการเปิด unsafe-inline และหากมีโครงสร้างโหลดสคริปต์ซับซ้อน อาจพิจารณา strict-dynamic อย่างรอบคอบ

ท้ายที่สุด CSP ไม่ใช่คำตอบแทนการแก้ช่องโหว่ในโค้ด แต่เป็นเครื่องมือที่ช่วยปิดความเสี่ยงได้อย่างมีชั้นเชิง และช่วยให้ทีมมีเวลาปรับปรุงระบบอย่างถูกทิศทางมากขึ้น