สรุปสั้น

เมื่อเว็บไซต์ใช้บริการ Cloudflare ซึ่งอยู่หน้าเว็บไซต์ราว 24.3% ของทั้งหมด บริษัท Cloudflare จะเพิ่มเส้นทาง /cdn-cgi/ ลงในโดเมนของเว็บนั้นเพื่อให้บริการฟีเจอร์ต่าง ๆ เช่น การตรวจบอต Web Analytics, Access และ Image Transformations หน้าเหล่านี้โหลดจากโดเมนของลูกค้าเอง บั๊กในเส้นทางนี้จึงได้สิทธิ์เท่ากับเว็บของลูกค้า ล่าสุดนาย Kevin Gervot และนาย Adam Kues นักวิจัยของบริษัท Searchlight Cyber เผยแพร่งานวิจัย “Cache Me If You Can” เมื่อ 28 ตุลาคม 2569 แสดงการร้อยจุดอ่อนเล็ก ๆ หลายจุดใน Image Transformations จนรัน JavaScript ผ่าน endpoint /cdn-cgi/image/ บน cloudflare.com ได้ ทั้งที่หน้านั้นตั้งนโยบายห้ามรันสคริปต์ไว้

หัวใจของเทคนิคนี้ คือ การใช้ header แคชที่ Cloudflare ส่งต่อจากรูปต้นทาง สั่งให้เบราว์เซอร์ตระกูล Chromium ทิ้ง Content Security Policy (CSP) ออกจากสำเนาที่เก็บในแคช แล้วบังคับให้โหลดสำเนานั้นซ้ำจนสคริปต์ทำงาน นักวิจัยใช้แนวคิดเดียวกันกับ Netlify Image CDN ได้ และชี้ว่า Amazon S3 กับ Google Cloud Storage ก็เปิดให้ลิงก์แบบ signed URL เขียนทับ header ได้ งานวิจัยไม่ระบุหมายเลข CVE หรือสถานะแพตช์ ทีมพัฒนาเว็บควรเลิกส่งต่อ header จากแหล่งที่ไม่น่าเชื่อถือ และตั้งค่า X-Content-Type-Options: nosniff

รายละเอียดข่าว

เว็บไซต์ Cyber Security News รายงานเมื่อวันที่ 28 ตุลาคม 2569 ว่านักวิจัยของ Searchlight Cyber ร้อยจุดอ่อนเล็ก ๆ หลายจุดในฟีเจอร์รูปภาพของ Cloudflare จนรัน JavaScript บนเว็บไซต์ที่ตั้งใจบล็อกสคริปต์ไว้ได้ ผลงานเผยแพร่ในชื่อ “Cache Me If You Can” โดยนาย Kevin Gervot และนาย Adam Kues

ด้านเป้าหมายที่สาธิต นักวิจัยแสดงช่องโหว่ cross-site scripting (XSS) ที่ใช้งานได้จริงผ่าน /cdn-cgi/image/ บนโดเมน cloudflare.com เอง XSS คือ การทำให้เบราว์เซอร์ของเหยื่อรันสคริปต์ของผู้โจมตีภายใต้สิทธิ์ของเว็บที่ถูกโจมตี ก่อนหน้านี้เคยมีนักวิจัยพบการเลี่ยง CSP ในเส้นทาง /cdn-cgi/ มาแล้ว

นอกจาก Cloudflare นักวิจัยทดสอบเทคนิคแคชกับ Netlify Image CDN และใช้ทิ้งได้ทั้ง CSP และ header Content-Type ส่วน Amazon S3 และ Google Cloud Storage ไม่ได้ถูกสาธิตการโจมตีเต็มรูปแบบ แต่ถูกยกเป็นตัวอย่างของบริการที่ signed URL กำหนด header ของการตอบกลับเองได้

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

รายละเอียดช่องโหว่

ขั้นที่ 1: SVG หลุดตัวกรอง — Cloudflare ทำความสะอาดไฟล์ SVG ด้วย svg-hush เครื่องมือที่เขียนด้วยภาษา Rust บนไลบรารี xml-rs เครื่องมือนี้ตรวจไฟล์ก่อน แล้วค่อยเขียนไฟล์ออกมาใหม่ นักวิจัยพบว่า xml-rs escape ค่า attribute ปกติ แต่เขียนค่า namespace (ค่าของ xmlns) ออกมาตรง ๆ ผู้โจมตีจึงซ่อนเครื่องหมายคำพูดในค่านั้นเพื่อหลุดออกจาก attribute ได้ ตัวกรองอนุมัติไฟล์ไปก่อนแล้ว แท็ก script จึงหลุดออกมาในไฟล์ผลลัพธ์

ขั้นที่ 2: ทำให้ CSP หายไปจากแคช — Cloudflare ส่งรูปเหล่านี้พร้อม CSP แบบเข้มงวด default-src ’none’ ซึ่งบล็อกสคริปต์ทั้งหมด แต่ endpoint ส่งต่อ header Cache-Control จากรูปต้นทางด้วย มาตรฐาน HTTP อนุญาตรูปแบบ no-cache=“Content-Security-Policy” ซึ่งบอกแคชให้ทิ้ง header ที่ระบุชื่อ มีเพียง Chromium ที่ทำตามกฎนี้และยอมรับชื่อ header ใดก็ได้ ผลคือการโหลดครั้งแรกยังมี CSP อยู่ แต่สำเนาที่ Chromium บันทึกไว้ในแคชไม่มี CSP แล้ว

ขั้นที่ 3: บังคับให้โหลดสำเนาจากแคช — นักวิจัยใช้เทคนิคที่รู้จักกันในวงการแข่ง CTF ผู้โจมตีเปิดหน้าในหน้าต่างใหม่ ย้ายหน้าต่างนั้นไปเว็บอื่น แล้วสั่ง history.back() เนื่องจากหน้าต่างยังผูกกับหน้าที่เปิดมัน (opener) Chromium จึงไม่ใช้ back/forward cache แต่ใช้ disk cache แทน สำเนาที่ไม่มี CSP จึงถูกโหลดและสคริปต์ทำงาน

ขั้นที่ 4: ดึงรูปจากที่ไหนก็ได้ — Image Transformations ดึงรูปเฉพาะจากแหล่งที่อนุญาต ค่าเริ่มต้น คือ “This zone only” แต่ตัวดึงรูปตาม redirect โดยไม่ตรวจที่อยู่ปลายทาง open redirect ใด ๆ บนเว็บที่อนุญาตจึงพาไปดึงไฟล์ของผู้โจมตีได้ นักวิจัยต้องการวิธีที่ไม่พึ่ง open redirect และพบว่าเมื่อเปิด Cloudflare Access กับ hostname ใดในโซน เส้นทาง /cdn-cgi/access/logout จะใช้ได้กับทุก hostname ในโซนนั้น และพารามิเตอร์ returnTo รับ subdomain ใดของ cloudflare.com ก็ได้ เมื่อรวมกับ redirect บนโฮสต์วิจัยของ Cloudflare เอง ตัวดึงรูปก็ถูกพาไปยังไฟล์ของผู้โจมตี ห่วงโซ่จึงครบแม้โซนจะตั้งค่าแหล่งรูปไว้เข้มงวด

ขยายผลไป Netlify, S3 และ GCS — บน Netlify Image CDN นักวิจัยใช้กลเม็ดแคชเดียวกันทิ้งทั้ง CSP และ Content-Type เมื่อไม่มี Content-Type Chromium จะเดาประเภทไฟล์จากเนื้อหา และมองไฟล์ SVG ที่ขึ้นต้นด้วย doctype เป็น HTML ส่วนสคริปต์ถูกซ่อนใน processing instruction ซึ่งตัวกรอง SVGO ไม่ตรวจเพราะดูเฉพาะ element สำหรับ Amazon S3 และ Google Cloud Storage ลิงก์แบบ signed URL กำหนด response-content-type และ response-cache-control ได้ จึงเสี่ยงกับ bucket ที่อยู่หลังโดเมนของเว็บเองหรือหลังพร็อกซีที่ส่งต่อ query string

ผลกระทบ

ผู้ที่ได้รับผลกระทบ คือ เว็บไซต์ที่ใช้ Cloudflare Image Transformations โดยเฉพาะโซนที่มี open redirect หรือเปิด Cloudflare Access ไว้ รวมถึงผู้ใช้ Netlify Image CDN และเว็บที่ให้บริการไฟล์จาก S3 หรือ GCS ผ่านโดเมนของตัวเอง ผลลัพธ์ของ XSS บนโดเมนจริง คือ ผู้โจมตีอ่านข้อมูลหน้าเว็บ ขโมยโทเคนที่เข้าถึงได้จาก JavaScript หรือสั่งการแทนผู้ใช้ที่ล็อกอินอยู่ได้ เพียงแค่ล่อให้เหยื่อเปิดลิงก์ด้วยเบราว์เซอร์ตระกูล Chromium ซึ่งเป็นเบราว์เซอร์ส่วนใหญ่ในตลาด

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

คำแนะนำ

  • สอบถามสถานะการแก้ไขจาก Cloudflare และ Netlify — ถ้าใช้ Image Transformations หรือ Image CDN ให้ติดตามประกาศของผู้ให้บริการ เพราะงานวิจัยไม่ระบุว่าแก้แล้วหรือยัง
  • ทบทวนแหล่งรูปที่อนุญาตใน Image Transformations — จำกัดให้แคบที่สุด และปิด open redirect ทุกจุดบนโดเมนที่อยู่ในรายการอนุญาต
  • ไม่ส่งต่อ header Cache-Control และ X- จากแหล่งที่ไม่น่าเชื่อถือ* — ถ้าระบบของคุณเป็นพร็อกซีหรือบริการประมวลผลไฟล์ ให้เขียน header เองแทนการคัดลอกจากต้นทาง
  • ตั้ง X-Content-Type-Options: nosniff ทุกการตอบกลับ — เพื่อไม่ให้เบราว์เซอร์เดาว่าไฟล์ SVG เป็น HTML เมื่อ Content-Type หายไป
  • ตรวจ bucket S3 และ GCS ที่อยู่หลังโดเมนของเว็บ — ไม่ให้พร็อกซีส่งต่อ query string อย่าง response-content-type และ response-cache-control ไปยัง bucket
  • ระยะยาว — แยกโดเมนสำหรับไฟล์ที่ผู้ใช้อัปโหลดหรือรูปจากภายนอกออกจากโดเมนหลักของแอปพลิเคชัน และใช้การป้องกันหลายชั้น ไม่พึ่ง CSP หรือตัวกรอง SVG เพียงอย่างเดียว

แหล่งอ้างอิง