CSP Evaluation Tool: ตรวจสอบและทำให้ Content Security Policy ของคุณแน่นหนาขึ้น
ใช้ CSP Evaluation Tool ตรวจสอบ Content-Security-Policy header ที่มีอยู่ เจอ unsafe-inline, wildcard และ fallback ที่ขาดหายไป พร้อมรับ suggested policy ที่แน่นหนาขึ้น
Table of Contents
Content-Security-Policy (CSP) ที่ดูเข้มงวดบนกระดาษ อาจอนุญาตมากกว่าที่คุณคิดเสมอ เพราะกฎการ fallback ของ default-src, keyword source ต่าง ๆ และ wildcard ทำให้สิ่งที่เบราว์เซอร์บังคับใช้จริงมักแตกต่างจากที่ header ดูเหมือนจะสื่อ CSP Evaluation Tool ให้คุณวาง policy ที่มีอยู่แล้วลงไป แล้วดูทีละ directive ว่า script source ตัวไหนที่มีผลจริงหลังจาก fallback chain ทำงานเสร็จสิ้น
เรื่องนี้สำคัญมาก เพราะ CSP เป็นหนึ่งในการป้องกัน XSS ที่ทรงพลังที่สุดในฝั่งไคลเอนต์ เมื่อทำงานถูกต้อง payload ที่ถูกฉีดเข้ามาจะโหลดหรือ execute ไม่ได้เลย แต่เมื่อตั้งค่าผิดพลาด policy จะให้ความรู้สึกปลอดภัยแบบหลอก ๆ: unsafe-inline เปิดให้ inline script ทำงานได้อีกครั้ง, wildcard อาจชี้ไปยัง host ที่คุณไม่ได้ควบคุม และ directive ที่คุณไม่เคยเขียนลงไปจะสืบทอดสิ่งที่ default-src อนุญาตโดยอัตโนมัติโดยที่คุณไม่รู้ตัว
บทความนี้จะอธิบายว่าทำไมการตรวจสอบ policy เดิมจึงคุ้มค่ากับเวลา วิธีอ่านผลลัพธ์จากเครื่องมือ และกลไก fallback ของ default-src ทำงานจริงอย่างไร
ทำไมต้องใช้ CSP Evaluation Tool?
- ตรวจสอบ policy ที่ได้รับสืบทอดมา — หลายทีมต้องรับ CSP ที่คนอื่นเขียนไว้เมื่อหลายปีก่อน และไม่มีใครจำได้ว่าแต่ละ source อยู่ในนั้นเพราะอะไร เครื่องมือนี้เปลี่ยนข้อความที่กำกวมให้เป็นรายการที่อ่านเข้าใจได้และตั้งคำถามได้
- เห็น effective source ที่แท้จริง — เครื่องมือคำนวณ source ที่มีผลของทุก directive หลัง fallback จาก default-src คุณจะไม่ต้องเดาอีกต่อไปว่าอะไรคุม script, style, image และ connection จริง ๆ
- เจอ unsafe-inline และ unsafe-eval — keyword สองตัวนี้คือจุดอ่อนคลาสสิกของ policy ทุกตัว เครื่องมือจะ flag ทุก directive ที่ยังใช้อยู่ พร้อมอธิบายความเสี่ยง XSS ในทางปฏิบัติ
- ตรวจจับ wildcard ที่เปิดให้ทุก host — wildcard สะดวกในวันนี้แต่อันตรายในวันหน้า เครื่องมือจะชี้จุดที่ควรระบุ host ให้แคบลงอย่างชัดเจน
- ระบุ directive ที่ไม่มี fallback — บาง directive ไม่สืบทอดจาก default-src เลย การขาดหายไปของรายการเหล่านี้คือรูรั่วจริงที่ไม่มีใครสังเกตจนถูกโจมตี
- ได้ suggested policy ที่พร้อมนำไปใช้ — policy ฉบับแนะนำมาพร้อมคำอธิบายของทุกการเปลี่ยนแปลง จึงค่อย ๆ นำไปใช้ทีละขั้นได้อย่างมั่นใจ
ฟีเจอร์หลัก
| ฟีเจอร์ | สิ่งที่ทำ |
|---|---|
| Effective source resolution | คำนวณว่าแต่ละ directive อนุญาตอะไรจริง ๆ หลัง fallback จาก default-src |
| Flag unsafe-inline / unsafe-eval | ระบุทุก directive ที่ยังใช้ keyword ที่หลวมเหล่านี้อยู่ |
| ตรวจจับ wildcard | หา source ที่เปิดให้ทุก host และแนะนำการระบุขอบเขตที่แคบลง |
| วิเคราะห์ fallback ที่ขาดหาย | แสดงรายการ directive ที่ไม่มี fallback รองรับเลย |
| Suggested hardened policy | ส่งมอบ policy ฉบับแนะนำพร้อมเหตุผลของแต่ละการเปลี่ยนแปลง |
| ทำงานฝั่ง client ทั้งหมด | การประเมินรันในเบราว์เซอร์ policy ของคุณไม่ออกจากเครื่อง |
รายละเอียดสองข้อที่ทำให้การใช้งานประจำวันง่ายขึ้น:
- ผลลัพธ์เรียงตามความรุนแรง ทำให้ปัญหาวิกฤตอย่าง unsafe-inline ใน script-src โผล่มาให้เห็นก่อน โดยไม่ต้องอ่านทั้ง policy ทีละบรรทัด
- ทุกการเปลี่ยนแปลงที่แนะนำมีคำอธิบายกำกับ ทำให้การรีวิวความปลอดภัยและการทำ pull request ราบรื่นขึ้นมาก
วิธีใช้ CSP Evaluation Tool
- คัดลอก CSP header ของคุณ ดึงมาจาก server หรือ proxy configuration, framework middleware หรือ response header ที่มองเห็นได้ใน DevTools ของเบราว์เซอร์
- วางลงในเครื่องมือ เปิด CSP Evaluation Tool แล้ววาง header string ลงในช่อง input ไม่มีการอัปโหลดข้อมูลใด ๆ
- อ่านผลลัพธ์ตามลำดับความรุนแรง เริ่มจากข้อวิกฤตก่อน: unsafe-inline หรือ unsafe-eval ใน script-src, wildcard ที่กว้างเกินไป และ data: หรือ blob: ที่คุณไม่คาดคิดว่าจะมี
- ดูการวิเคราะห์ fallback ตรวจมุมมองราย directive เพื่อดูว่า source ไหนระบุไว้ตรง ๆ และ source ไหนสืบทอดมาจาก default-src รวมถึง directive ใดที่ไม่มี fallback เลย
- นำ suggested policy ไปใช้ทีละขั้น เริ่มจากโหมด report-only ก่อน ยืนยันว่าสิ่งที่ใช้งานจริงไม่พัง แล้วค่อยบังคับใช้ โดยทุกการเปลี่ยนแปลงมีเอกสารกำกับไว้แล้ว
กลไก fallback ของ default-src ทำงานจริงอย่างไร
การสืบทอดจาก directive เมื่อ fetch directive เช่น script-src, style-src, img-src, connect-src หรือ frame-src ไม่ปรากฏใน policy เบราว์เซอร์จะ fallback ไปใช้ค่าของ default-src ถ้าคุณมีแค่ default-src 'self' https://cdn.example.com ภาพ ฟอนต์ XHR และ frame ทั้งหมดจะสืบทอดแค่สอง source นี้เท่านั้น จุดที่ละเอียดอ่อนคือ fallback มีผลเฉพาะ directive ที่ไม่ได้เขียนไว้เท่านั้น ทันทีที่คุณเพิ่ม img-src data: ภาพจะโหลดจาก data URI ได้ แม้ default-src จะบอกอย่างอื่น เพราะ directive ที่ระบุชัดเจนจะแทนที่ fallback ทั้งหมดของ resource type นั้น
ทำไม unsafe-inline จึงทำให้ script-src อ่อนแอโดยไม่รู้ตัว การ execute inline script คือช่องทางหลักของ payload XSS ด้วย default-src 'self' เพียงอย่างเดียว inline script จะถูกบล็อกทั้งหมด แต่พอวันหนึ่งใครสักคนเพิ่ม script-src 'unsafe-inline' เพื่อให้ widget เก่าตัวเดียวทำงานได้ ทุก inline event handler และ script block ที่ถูกฉีดใน user-generated content ก็ execute ได้อีกครั้ง การเปลี่ยนแปลงใน diff ดูเล็กน้อยมาก แต่ตัด protection ส่วนใหญ่ของ policy ทิ้งไปเฉย ๆ
Wildcard และการกำหนดขอบเขต host เครื่องหมาย _ เปล่า ๆ อนุญาตทุก host และทำให้แนวคิด allow-list ไร้ความหมายทันที wildcard ย่อยอย่าง _.example.com แคบกว่าแต่ยังต้องเชื่อใจทุก subdomain ไปตลอดกาล การกำหนดขอบเขตให้แคบต่อ directive เช่น script จาก CDN เดียว และ connection ไปที่ API ของคุณเท่านั้น คือสิ่งที่ทำให้ policy ยังตรวจสอบได้หลังผ่านไปหลายเดือน
Directive ที่ไม่มี fallback ที่โดดเด่นที่สุดคือ base-uri และ frame-ancestors ซึ่งไม่สืบทอดจาก default-src ถ้า base-uri หายไป HTML ที่ถูกฉีดจะเปลี่ยนเส้นทาง URL แบบ relative ไปที่ใดก็ได้ ถ้า frame-ancestors หายไปใครก็ตามสามารถ frame หน้าเว็บของคุณได้ เครื่องมือจะแสดงรายการกลุ่มนี้อย่างชัดเจนเพื่อไม่ให้ถูกลืมอีก
โหมด report-only สำหรับการเปิดตัวอย่างปลอดภัย header Content-Security-Policy-Report-Only จะบังคับใช้ policy โดยไม่บล็อกอะไรเลย แต่รายงาน violation แทน นี่คือวิธีที่แนะนำในการเปิด policy ใหม่: ดูรายงานจาก traffic จริง แก้ช่องโหว่ที่พบ แล้วค่อยเปลี่ยนเป็น enforcement โดยไม่มีความเสี่ยง downtime เลยแม้แต่นาทีเดียว
กรณีใช้งานจริง
ตรวจสอบแอปที่ได้รับสืบทอดมา
คุณเข้าทีมใหม่และรับ SPA ตัวเก่าที่มี CSP ที่ไม่มีใครกล้าแตะ วาง production header ลงในเครื่องมือ: ภายในไม่กี่วินาทีคุณจะรู้ว่า script-src มี unsafe-inline ตกค้างจาก plugin เก่า, img-src มี wildcard ที่หลงเหลือจาก image proxy ที่เลิกใช้ไปนานแล้ว และ form-action ไม่เคยถูกตั้งค่าเลยตั้งแต่วันแรก นั่นคือรายการที่ชัดเจนและจัดลำดับความสำคัญได้ แทนความรู้สึกคลุมเครือว่า policy อ่อนแอ
รีวิวความปลอดภัยก่อนเปิดตัว
ก่อนปล่อยผลิตภัณฑ์ที่หันหน้าเข้าหาลูกค้า ให้รัน CSP ผ่านการประเมินเป็นส่วนหนึ่งของ launch checklist คุณจะยืนยันได้ว่า build ไม่หล่น unsafe-eval เข้า production, host ของ analytics ถูกระบุแม่นยำ และ base-uri กับ frame-ancestors มีอยู่จริง การจับปัญหาก่อนเปิดตัวใช้เวลาไม่กี่นาที แต่การจับหลังเปิดตัวคือ incident เต็มรูปแบบ
รัดกุมขึ้นหลังเจอผลจาก pentest
รายงาน pentest บอกว่า tester ทำ XSS ได้แต่ exfiltrate ข้อมูลได้ไม่ไกล ให้คัดลอก header มาประเมิน แล้วดูว่า directive ไหนปล่อย payload ให้ผ่านเข้ามา นำ suggested policy ไปใช้ ปล่อยแบบ report-only สักหนึ่งสัปดาห์ ตรวจว่ารายงานสะอาด แล้วบังคับใช้จริง พร้อมแนบผลประเมินก่อน-หลังไว้ในเอกสารการแก้ไขของรายงาน pentest ด้วย
ย้ายจาก unsafe-inline ไปใช้ nonce และ hash
เป้าหมายสุดท้ายของ policy ทุกตัวคือการเอา unsafe-inline ออกจาก script-src และ style-src เส้นทางการย้ายคือ serve nonce ต่อ request ให้กับ inline script ที่ถูกต้องตามกฎหมาย หรือคำนวณ hash ของ inline block แบบ static แล้วระบุเป็น source แบบ sha256- จากนั้นประเมินใหม่หลังแต่ละขั้นตอนเพื่อยืนยันว่าไม่เหลือ keyword ที่หลวม และไม่มีส่วนอื่นอ่อนแอตามมาโดยไม่รู้ตัว
แนวปฏิบัติที่ดี
- เปิด policy ใหม่เป็น report-only ก่อนเสมอ การบังคับใช้โดยไม่สังเกตผลก่อนคือการทำ production พัง ให้รายงานบอกคุณว่า traffic จริงต้องการอะไร
- แทนที่ unsafe-inline ด้วย nonce หรือ hash การเปลี่ยนแปลงเพียงอย่างเดียวนี้ตัดเส้นทางการโจมตี XSS ในทางปฏิบัติได้ส่วนใหญ่
- รักษา policy ให้ตรงกับโค้ดเสมอ ทุก third-party script หรือ analytics ที่เพิ่มเข้าแอปควรทริกเกอร์การรีวิว policy ไม่ใช่การขยาย fallback ให้กว้างขึ้น
- ประเมินใหม่หลัง third-party เปลี่ยนแปลง vendor ย้าย endpoint และรวมโดเมนกันเสมอ ให้รันการประเมินทุกครั้งที่พฤติกรรมการโหลดของ dependency เปลี่ยนไป
- กำหนดขอบเขต source ต่อ directive แก้ violation ด้วยการเพิ่ม source ที่แคบที่สุดให้ directive ที่ต้องการเท่านั้น ไม่ใช่การขยาย default-src
- จดเหตุผลว่าแต่ละ source อยู่ในนั้นทำไม คำอธิบายการเปลี่ยนแปลงจากเครื่องมือเป็นจุดเริ่มต้นที่ดีของบันทึกที่คุณเก็บไว้ข้าง header configuration
ตรวจสอบครั้งหนึ่งแล้วทำให้เป็นนิสัย: วาง header ของคุณลงใน CSP Evaluation Tool อ่านผลลัพธ์ แล้วปล่อย policy ที่คุณอธิบายได้จริง — ทีละ directive
เครื่องมือที่เกี่ยวข้องที่คุณอาจสนใจ:
- CSP Generator — สร้าง policy ที่เข้มงวดตั้งแต่ต้น เมื่อคุณพร้อมจะเขียนใหม่ทั้งหมด
- Security Headers Generator — เติมเต็มภาพรวมด้วย HTTP security header อื่น ๆ
- Hash Generator — คำนวณ SHA-256 hash ที่ต้องใช้สำหรับ allow-list inline script
ขอให้ปลอดภัยทุกการ deploy ครับ!
คำถามที่พบบ่อย
ถ: CSP evaluation กับ CSP generation ต่างกันอย่างไร? ตอบ: evaluation วิเคราะห์ policy ที่คุณ deploy อยู่แล้ว โดยคำนวณ effective source และ flag unsafe-inline, wildcard และ fallback ที่ขาดหายไป ส่วน generation สร้าง policy ใหม่จากความต้องการ ในทางปฏิบัติมัก generate ก่อน แล้วประเมินและปรับกับสิ่งที่ใช้งานจริง
ถ: ทำไมเครื่องมือแสดง source ของ directive ที่ผมไม่เคยเขียนลงไป? ตอบ: นั่นคือ fallback จาก default-src ทุก fetch directive ที่ไม่ปรากฏจะสืบทอดค่า default-src และเครื่องมือคำนวณให้ราย directive เพื่อให้คุณเห็น policy ที่เบราว์เซอร์บังคับใช้จริง ไม่ใช่แค่ตัวที่คุณพิมพ์ไว้
ถ: policy ของผมถูกส่งไป server หรือไม่เมื่อวางลงเครื่องมือ? ตอบ: ไม่ การประเมินทั้งหมดทำงานในเบราว์เซอร์ของคุณ ไม่มีการอัปโหลด เก็บ หรือ log ข้อมูลใด ๆ จึงปลอดภัยแม้กับ policy ภายในองค์กรหรือเฉพาะลูกค้า
ถ: เครื่องมือแก้ policy ให้อัตโนมัติได้หรือไม่? ตอบ: เครื่องมือสร้าง suggested hardened policy พร้อมคำอธิบายทุกการเปลี่ยนแปลง แต่การนำไปใช้ยังคงเป็นแบบ manual โดยตั้งใจ เพราะ CSP โต้ตอบกับการโหลด resource จริงของแอป เส้นทางที่ปลอดภัยคือ report-only ก่อน ตรวจสอบ แล้วบังคับใช้