2 คะแนน โดย GN⁺ 4 시간 전 | 1 ความคิดเห็น | แชร์ทาง WhatsApp
  • ช่องโหว่ของเว็บเซิร์ฟเวอร์โลคัลของ Zoom แสดงให้เห็นว่าเมื่อเว็บดีเวลอปเปอร์จำนวนมากเข้าใจ วิธีการทำงานของ CORS ผิดพลาด ขอบเขตความปลอดภัยก็อาจพังทลายลงได้ง่าย
  • Zoom สื่อสารกับเซิร์ฟเวอร์โลคัล localhost:19421 และใช้ ขนาดของรูปภาพ เพื่อส่งรหัสสถานะแทน AJAX ซึ่งตีความได้ว่าเป็นการทำทางอ้อมเพื่อหลบเลี่ยง CORS
  • Chrome ใช้ CORS header กับเว็บเซิร์ฟเวอร์บน localhost ด้วย และการสื่อสารระหว่างฟรอนต์เอนด์กับแบ็กเอนด์ที่อยู่คนละพอร์ตบน localhost ก็ได้รับการรองรับในเบราว์เซอร์
  • การออกแบบที่ปลอดภัยกว่าคือให้เซิร์ฟเวอร์โลคัลมี REST API และตั้งค่า Access-Control-Allow-Origin เพื่อจำกัดให้เฉพาะ JavaScript ของ zoom.us เข้าถึงได้
  • การหลบเลี่ยง same-origin policy อาจทำให้โค้ดทำงานได้ แต่ฟังก์ชันที่มีสิทธิ์ของเซิร์ฟเวอร์โลคัลอาจถูกเปิดเผยให้ทุกเว็บไซต์บนอินเทอร์เน็ตเข้าถึงได้

การหลบเลี่ยง CORS ที่เกิดจากเว็บเซิร์ฟเวอร์โลคัลของ Zoom

  • จากการทำงานที่ปรึกษาแบบฟูลสแต็กกับนักพัฒนาหลายขนาดหลายอุตสาหกรรม พบซ้ำๆ ว่าเว็บดีเวลอปเปอร์จำนวนมากไม่เข้าใจ CORS
  • ใน ช่องโหว่ล่าสุดของ Zoom นักวิจัยความปลอดภัย Jonathan Leitschuh พบว่า Zoom เปิดเว็บเซิร์ฟเวอร์ http://localhost:19421 ไว้บนเครื่องผู้ใช้
    • เมื่อผู้ใช้เปิดลิงก์ Zoom เว็บไซต์ Zoom จะส่งคำขอไปยังเว็บเซิร์ฟเวอร์บน localhost เพื่อเรียกแอป Zoom แบบเนทีฟขึ้นมา
    • แทนที่จะใช้คำขอ AJAX ปกติ ระบบกลับโหลดรูปภาพจากเว็บเซิร์ฟเวอร์โลคัลของ Zoom และใช้ขนาดรูปที่ต่างกันเพื่อสื่อถึงข้อผิดพลาดและรหัสสถานะของเซิร์ฟเวอร์
  • การตีความว่าบราว์เซอร์เพิกเฉยนโยบาย CORS ของเซิร์ฟเวอร์ localhost นั้นไม่ถูกต้อง และ Chrome ก็ เคารพ CORS header ของเว็บเซิร์ฟเวอร์บน localhost
    • แม้ตอนรันฟรอนต์เอนด์ของ Create React App และแบ็กเอนด์ API คนละพอร์ตบน localhost ก็ยังเกิดคำขอข้ามต้นทาง และเบราว์เซอร์ทั้งหมดรองรับกรณีนี้
  • ดูเหมือนว่าเมื่อคำขอ AJAX ถูกบล็อก Zoom จึงใช้เทคนิค image hack เพื่อหลบเลี่ยง CORS
    • ผลคือไม่ใช่แค่เว็บไซต์ Zoom เท่านั้น แต่เว็บไซต์อื่นๆ บนอินเทอร์เน็ตก็สามารถทริกเกอร์การทำงานของไคลเอนต์เนทีฟและเข้าถึงการตอบสนองได้ด้วย

ทางเลือกที่ปลอดภัยกว่าและปัญหา UX ที่ยังคงอยู่

  • แนวทางที่ปลอดภัยคือให้เว็บเซิร์ฟเวอร์บน localhost:19421 ทำงานเป็น REST API และตั้งค่า header Access-Control-Allow-Origin เป็น https://zoom.us
    • แบบนี้จะมีเพียง JavaScript ที่รันอยู่บนโดเมน zoom.us เท่านั้นที่สื่อสารกับเว็บเซิร์ฟเวอร์บน localhost ได้
    • zoom.us ยังสามารถใส่ header Content Security Policy เพื่อบล็อกการเรนเดอร์ iframe และป้องกันไม่ให้ Zoom meeting เปิดขึ้นมาอัตโนมัติในเบื้องหลังได้
  • ปัญหาที่หน้าเว็บใดๆ ก็ยังสามารถรีไดเรกต์เบราว์เซอร์ไปยังลิงก์ประชุมของ zoom.us ได้ ยังคงมีอยู่
    • อย่างไรก็ตาม นี่ใกล้เคียงกับ ประสบการณ์ผู้ใช้ ที่ Zoom เลือกมากกว่าจะเป็นช่องโหว่ซอฟต์แวร์
    • Zoom กำลังทำลายความคาดหวังของผู้ใช้ที่คิดว่าเมื่อคลิกลิงก์ กล้องและไมโครโฟนจะไม่ถูกเปิดให้คนแปลกหน้าโดยกะทันหัน
    • หากต้องการหลีกเลี่ยงป๊อปอัปของเบราว์เซอร์ด้วยเหตุผลด้าน UX ก็สามารถแสดงป๊อปอัปภายในแอปได้ และ Google Meet ก็ใช้วิธีนี้ได้ดี
  • การรันเว็บเซิร์ฟเวอร์บน localhost เองก็เป็นความพยายามที่เสี่ยงอยู่แล้ว และโดยเฉพาะอย่างยิ่งไม่ควรเปิดฟังก์ชันที่มีสิทธิ์ เช่น การติดตั้งซอฟต์แวร์ ให้ทุกเว็บไซต์บนอินเทอร์เน็ตใช้งานได้
    • CORS ถูกสร้างมาเพื่อจัดการสถานการณ์แบบนี้อย่างปลอดภัย จึงไม่ควรถูกหลบเลี่ยง

ความสับสนเรื่อง CORS ไม่ใช่ความผิดพลาดของ Zoom เจ้าเดียว

  • ยังไม่แน่ชัดว่า Zoom เลือกวิธีนี้เพราะไม่เข้าใจ CORS จริงหรือไม่
    • lerunicorn บน Reddit มองว่า Firefox อาจบล็อก XHR จากต้นทางที่ปลอดภัยไปยังต้นทางที่ไม่ปลอดภัย
    • แต่ Firefox รองรับกรณีนี้เมื่อ origin เป็น localhost
    • แอปเนทีฟสามารถสร้างใบรับรองแบบ self-signed ของตัวเองได้ และยังใช้ ส่วนขยายเบราว์เซอร์ ได้ด้วย
    • ไม่ว่าในกรณีใดก็ไม่ใช่เหตุผลอันชอบธรรมที่จะละเว้น การกรองต้นทาง
  • ความสับสนเรื่อง CORS ไม่ได้เกิดกับ Zoom เท่านั้น
  • นักพัฒนาต้องการให้โค้ดทำงานได้ แต่หากหลบเลี่ยง same-origin policy ทั้งหมด ก็จะทำให้สิทธิ์บนเครื่องโลคัลถูกเปิดเผยให้เว็บไซต์ภายนอกเหมือนกรณีของ Zoom
  • ความสับสนเรื่อง CORS พบได้ทั้งในนักพัฒนาที่มีประสบการณ์และมือใหม่ ยังไม่ชัดเจนว่าเป็นเพราะ CORS API ซับซ้อนเกินไปหรือเพราะการสอนเรื่อง CORS และ CSP ยังไม่เพียงพอ แต่แนวทางปัจจุบันก็ทำงานได้ไม่ดีนัก

1 ความคิดเห็น

 
GN⁺ 4 시간 전
ความคิดเห็นจาก Hacker News
  • ดูเหมือนว่าแม้แต่บทความต้นทางก็ยังไม่เข้าใจ CORS อย่างถูกต้อง หรืออธิบายผิดอย่างมาก
    Access-Control-Allow-Origin: https://zoom.us ไม่ได้ทำให้มั่นใจว่าเฉพาะ JavaScript จากโดเมน zoom.us เท่านั้นที่จะสื่อสารกับเซิร์ฟเวอร์ localhost ได้ JavaScript จากเว็บไซต์อื่นก็ยังส่งคำขอไปที่ localhost:19421 ได้เหมือนกัน CORS ไม่ได้มีไว้เพื่อจำกัดอะไร แต่เป็นกลไกที่ใช้ผ่อนคลายข้อจำกัดที่มีอยู่เดิม ส่วน header นี้เพียงแค่ทำให้ JavaScript ที่รันอยู่บน zoom.us อ่านการตอบกลับจาก localhost:19421 ได้เท่านั้น และเนื่องจากตัวคำขอจะเกิดขึ้นอยู่แล้ว ฝั่งแบ็กเอนด์จึงต้องออกแบบไม่ให้เกิดผลข้างเคียง

    • ไม่เข้าใจว่าทำไมคอมเมนต์นี้ถึงได้คะแนนโหวตสูงสุด OP ถูกแล้ว ส่วนคำอธิบายข้างต้นผิด
      คำขอ GET นั้นถูกส่งออกไปได้จริง แต่ตามหลักแล้วควรเป็นแบบ idempotent ดังนั้นถ้าเซิร์ฟเวอร์อิมพลีเมนต์ ถูกต้องก็ไม่ควรทำให้เกิดผลข้างเคียง และสำหรับ GET ประเด็นสำคัญคืออ่านการตอบกลับได้หรือไม่ ในทางกลับกัน คำขอแบบ non-idempotent ที่อาจมีผลข้างเคียง ในสถานการณ์ข้ามแหล่งที่มาจะมีการส่งคำขอ preflight OPTIONS ก่อนแทนคำขอจริง และถ้าการตอบกลับของ OPTIONS ไม่มี header ที่ถูกต้อง คำขอจริงจะไม่ถูกส่ง
    • ผมก็ไม่คิดว่าจะพูดได้ว่า CORS ทำหน้าที่แบบนั้น
      ความเข้าใจผิดเกี่ยวกับ CORS แพร่หลายมาก และเอกสารก็มักขัดแย้งกันเอง จึงยากที่จะคาดหวังว่าคู่สนทนาที่เราไม่รู้จักจะติดตั้งใช้งานได้ถูกต้อง ถ้าโปรโตคอลหนึ่งก่อให้เกิดความสับสนอย่างกว้างขวางขนาดนี้ ต่อให้ฝั่งหนึ่งทำงานถูกต้อง ก็ไม่อาจรู้ได้ว่าอีกฝั่งจะถูกต้องด้วยหรือไม่ ถ้าผู้คนแก้โค้ดไปเรื่อย ๆ จนมันทำงานกับ implementation ของอีกฝ่ายได้ ก็ยิ่งไม่ชัดว่าฝั่งตัวเองผิดหรืออีกฝ่ายผิดกันแน่
    • เท่าที่ผมเข้าใจ จุดประสงค์หลักของ preflight OPTIONS คือการบล็อกคำขอ HTTP ที่ตามปกติจะไม่ถูกอนุญาต ส่วนคำขอที่เดิมอนุญาตอยู่แล้ว CORS จะไม่ทำอะไร
      ตัวอย่างเช่น POST ที่มี Content-Type เป็น text/json จะส่งไปยังโฮสต์บุคคลที่สามโดยไม่มี OPTIONS preflight ไม่ได้ แต่ POST ที่เป็น multipart/form-data นั้นอนุญาต และ CORS จะไม่บล็อก แล้วถ้า endpoint ไม่ตรวจสอบ Content-Type อย่างเข้มงวดและสมมติว่าเป็น JSON ไปเลย ก็เท่ากับว่าเว็บไซต์ใดก็ได้สามารถส่ง POST ได้โดยที่ผู้ใช้ไม่ต้องโต้ตอบอะไร
    • การบอกว่า “สมมติว่าพูดถึงเฉพาะเมธอดที่ปลอดภัย” เป็นสมมติฐานที่ค่อนข้างใหญ่
      นักพัฒนาเว็บที่ดีไม่ควรทำให้ GET/HEAD/OPTIONS เปลี่ยนสถานะ และการเข้าร่วมประชุมก็เป็นการเปลี่ยนสถานะ ส่วน PUT/DELETE ก็ควรเป็น idempotent เช่นกัน API แบบ POST ที่ไม่ใช่ JSON หรือฟอร์มควรตรวจสอบ header Content-Type และ POST ที่ใช้ PUT/PATCH/DELETE หรือ Content-Type ที่ไม่ใช่รูปแบบฟอร์ม จะกระตุ้น preflight ทำให้ CORS ถูกตรวจสอบก่อนที่คำขอจริงจะไปถึงเซิร์ฟเวอร์
    • ส่วนในบทความที่บอกว่า “แอปเนทีฟสามารถสร้าง ใบรับรองแบบ self-signed ของตัวเองได้” ก็มีปัญหาเช่นกัน
      แค่สร้างใบรับรองขึ้นมาอย่างเดียวใช้ไม่ได้ มันต้องถูกติดตั้งเป็นใบรับรอง root CA ลงใน trust store ของเบราว์เซอร์ทั้งหมดบนเครื่องนั้นด้วย ถ้า private key ของ root CA ไม่ได้รับการปกป้องอย่างเหมาะสม เว็บไซต์ใด ๆ ก็สามารถทำ man-in-the-middle attack ได้ ดังนั้นอย่างน้อยควรมี name constraints (https://datatracker.ietf.org/doc/html/rfc5280#section-4.2.1.10) แต่ใน Chrome ก่อน v112 ปี 2023 สิ่งนี้ใช้กับ root CA ไม่ได้ (https://alexsci.com/blog/name-non-constraint/) จึงต้องเพิ่ม intermediate CA แล้วไปใส่ข้อจำกัดไว้ตรงนั้น แน่นอนว่าควรทิ้งคีย์ root CA ไปเลย
      ก่อนหน้านี้ผมเคยเพิ่ม basic constraints ในโปรเจกต์ที่ใช้ local root CA แต่ใส่ผิดไว้ที่ root CA และก็ไม่ได้ทดสอบกับทุกเบราว์เซอร์ด้วย
  • อยากให้มีคนอ่าน เอกสาร CORS ของ MDN มากกว่านี้ มันช่วยผมได้มากตอนพยายามทำความเข้าใจ CORS และพอมาเห็นคอมเมนต์ที่นี่ก็เพิ่งรู้ว่าผู้คนรู้สึกว่ายากกันขนาดนี้
    https://developer.mozilla.org/en-US/docs/Web/HTTP/Guides/CORS

    • แค่เอกสารนั้นอันเดียวก็ตอบได้เกือบทั้งหมด ทั้งกรณี origin แบบง่าย ๆ และ วิธีการทำงานของ preflight
  • สิ่งที่เข้าใจยากไม่ใช่แค่ CORS แต่คือนักพัฒนาจำนวนมากไม่เข้าใจ threat model อย่างแท้จริง
    ต่อให้ฟังคำอธิบายแล้ว หลายครั้งก็ยังนึกภาพไม่ออกว่าทำไมมันถึงเป็นปัญหาใหญ่ โดยเฉพาะเมื่อแบ็กเอนด์เป็นฝ่ายต้องตั้งค่า CORS บ่อย ๆ แต่ CORS ไม่ใช่กลไกปกป้องสิทธิ์การเข้าถึง ดังนั้นจากมุมมองของแบ็กเอนด์มันเลยดูไม่สำคัญนัก ผู้โจมตีเหมือนจะเอาอะไรไปไม่ได้ ขณะที่ฝั่งฟรอนต์เอนด์ก็มักมองว่าเป็นอุปสรรคที่น่ารำคาญ บทความนี้แสดงตัวอย่างที่เป็นรูปธรรมได้ดี

    • แม้แต่ในโปรเจกต์ที่นักพัฒนาคนเดียวกันเขียนทั้งฟรอนต์เอนด์และแบ็กเอนด์ ก็ยังเคยตั้งค่า CORS ผิด
      ในฐานะผู้ดูแลระบบ ผมจึงไปแก้ให้ถูกต้องอีกครั้งที่ load balancer และอย่างน้อยตอนนี้แอปพลิเคชันก็ใช้งานได้แล้ว CORS เข้าใจยากก็จริง แต่ที่น่าเสียดายกว่าคือมีนักพัฒนาจำนวนมากที่ไม่เข้าใจทั้ง threat model ที่ CORS พยายามป้องกัน และการพัฒนาเว็บโดยรวม โดยเฉพาะ HTTP protocol
    • threat model ของ CORS ไม่ได้ยากขนาดนั้น มันคือสถานการณ์ที่ผู้โจมตีล่อให้ผู้ใช้เข้าไปยังเว็บไซต์ของตน แล้วทำให้เบราว์เซอร์ไปกระทำบางอย่างกับเว็บไซต์ของคุณ
    • CORS ชวนสับสนเพราะมันถูกวางทับอยู่บนโมเดลสิทธิ์เริ่มต้นที่ค่อนข้างแปลก เช่น multipart/form-data ใช้ได้ แต่ JavaScript ของแอปพลิเคชันกลับไม่ได้
    • ถ้ามองจากมุมของผู้โจมตีและผู้ป้องกัน threat model นี้ก็ไม่ได้เป็นธรรมชาติเท่าไร
      CORS เป็นสิ่งที่เลือกใช้ได้ และไลบรารีหรือเครื่องมืออื่นอาจเมินมันไปเลยก็ได้ CORS มีความหมายจริง ๆ แค่กับการป้องกัน XSS และ CSRF ต่อผู้ใช้จริงที่ล็อกอินอยู่ ส่วนสถานการณ์โจมตีแบบอื่นก็ไม่มีความหมาย เพราะยังไงก็ใช้สคริปต์หรือโปรแกรมที่ปลอม HTTP header ได้อยู่แล้ว สุดท้ายผู้คนจึงเปิดตัวเลือก CORS ทั้งหมดทิ้งไว้ ซึ่งเป็นกรณีเลวร้ายที่สุดเพราะเท่ากับยอมให้เกิด XSS และ CSRF
    • CORS ยอดเยี่ยมมากในการทำให้ผู้คนขโมยแบนด์วิดท์และทรัพยากรโฮสต์ได้ยากขึ้น ถ้าจะขโมยก็ต้องตั้ง proxy เอง ซึ่งทำให้บล็อกได้ง่ายขึ้น
  • อ่านคอมเมนต์แล้วรู้สึกว่าระดับข้อมูลในนี้ต่ำมาก และยิ่งพิสูจน์ประเด็นของผู้เขียนตรงๆ

    • อาจเป็นเรื่องของช่องว่างระหว่างยุคสมัยก็ได้
      ถ้าเคยพัฒนาเว็บมาก่อนที่ CORS จะเกิดขึ้น ก็จะเข้าใจว่าเดิมที cross-domain requests ถูกห้ามอยู่แล้ว และ CORS เกิดขึ้นมาเพื่อผ่อนข้อจำกัดด้านความปลอดภัยนี้ ดังนั้นจึงรับได้ง่ายว่าถ้าอยากให้ทำงานที่ต้องการ ก็แค่เปิดใช้ CORS
      ในทางกลับกัน คนที่เริ่มเรียนพัฒนาเว็บหลังยุค CORS จะเห็นแค่ลำดับว่า ลองทำ cross-origin request, เบราว์เซอร์ตัดสินว่าไม่อนุญาต, ลองทำ CORS preflight, แล้วพอล้มเหลวก็มี CORS error ขึ้นในคอนโซล ถ้าไม่รู้การทำงานภายในและไม่ได้อ่านเอกสาร ก็มักเดาว่า CORS คือสาเหตุที่บล็อกคำขอ แล้วพยายาม “ปิดการทำงานของ CORS” แต่จริงๆ แล้ว CORS ไม่ใช่ต้นเหตุของปัญหา มันคือทางแก้
      พอมีคนที่เข้าใจผิดแบบเดียวกันพูดซ้ำอย่างมั่นใจใน tutorial และการถกเถียงออนไลน์ ก็ยิ่งทำให้งงมากขึ้น
    • CORS ไม่ได้เป็นเรื่องที่เข้าใจได้จากสัญชาตญาณ แต่ถ้าอ่านเอกสารก็เข้าใจได้
      https://developer.mozilla.org/en-US/docs/Web/HTTP/Guides/CORS
  • พออ่านคอมเมนต์ก็ยืนยันได้ว่าไม่ได้มีแค่ฉันที่เป็นแบบนี้ เหตุผลที่ไม่มีใครเข้าใจ CORS จริงๆ คือ มันซับซ้อนเกินไปและมีจุดขัดกันเยอะมาก
    ทั้งมาตรฐานและเฮดเดอร์ก็เปลี่ยนตลอด นักพัฒนาส่วนใหญ่เลยมักลองปรับโน่นนี่ไปเรื่อยๆ จนกว่าจะใช้งานได้ แล้วก็ปล่อยโปรดักต์ออกไปจบ แม้จะทำงานได้ แต่ใน developer console อาจยังมี error กับ warning อยู่ ทว่าถ้าภายนอกดูเหมือนทำงานปกติดี ก็มักจะไม่ไปแตะมันอีก

  • ถ้าอยากเข้าใจ CORS ต้องเข้าใจ same-origin policy ก่อน
    โดยเฉพาะถ้าคำถามว่า “ทำไมสิ่งนี้ถึงจำเป็น?” ยังตอบยาก จุดเริ่มต้นที่ดีคือ: https://developer.mozilla.org/en-US/docs/Web/Security/Defenses/Same-origin_policy
    เมื่อก่อนเคยใช้ same-origin policy เป็นคำถามสัมภาษณ์ แต่ผู้สมัครจำนวนมากไม่คุ้นเคยกับมัน เลยทำให้คำถามนี้ให้ข้อมูลได้ไม่มากนัก

    • ฉันว่าเป็นคำถามที่ค่อนข้างดีเวลาเลือก frontend developer
      เพราะถ้าเคยพัฒนาเว็บแอปมา ยังไงสักวันก็ต้องเคยเจอ same-origin policy ถ้าไม่รู้จัก ก็มักต้องถามต่อว่าแล้วสื่อสารกับ backend อย่างไร เป็นต้น เคยเจอปัญหา CORS แต่เลือกใช้แค่ทางลัดที่เร็วที่สุดแล้วลืมมันไป หรือเคยพยายามทำความเข้าใจจริงๆ ไหม เรื่องนี้เป็นสัญญาณที่มีประโยชน์สำหรับบางบทบาท
      แต่สำหรับตำแหน่ง backend จะเหมาะน้อยกว่า เพราะไม่ใช่นักพัฒนา backend ทุกคนจะได้ทำงานใกล้ชิดกับทีม frontend ที่ต้องเจอปัญหา CORS บ่อยๆ
  • สิ่งที่จำได้เกี่ยวกับ CORS คือการดีบักใช้เวลานานกว่าที่คิดมาก ข้อความผิดพลาดจากเบราว์เซอร์ก็ตั้งใจทำให้ข้อมูลน้อย และ CORS error ก็แยกจากรูปแบบความล้มเหลวอื่นได้ยากในตอนแรก

    • CORS error ไม่ใช่ “ข้อความผิดพลาดที่ถูกส่งมาจากเบราว์เซอร์” แต่เป็นข้อผิดพลาดที่เบราว์เซอร์สร้างขึ้นเพราะตัดสินว่าไม่สามารถอนุญาตคำขอนั้นได้
      แน่นอนว่าถ้าเซิร์ฟเวอร์ไม่เข้าใจ CORS request แล้วคืน response แปลกๆ มา สุดท้ายมันก็อาจถูกตีความเป็น CORS failure ได้
  • อ่านคอมเมนต์แล้วค่อนข้างสนุก เลยขอเสริมว่า same-origin policy ป้องกันไม่ให้เบราว์เซอร์รั่วไหลข้อมูลไปยังเว็บไซต์ที่ไม่มีสิทธิ์เข้าถึง และ CORS ทำให้สามารถลดความเข้มของการป้องกันนั้นได้
    ตัวอย่างเช่น same-origin policy จะกันไม่ให้ example.com ดึงรายการสมัครรับข้อมูลของ youtube.com มาได้ แต่ถ้าใช้ CORS ก็อาจอนุญาตให้ example.com เข้าถึง youtube.com/public/* ได้
    อีกการใช้งานหนึ่งคือช่วยป้องกันไม่ให้ backend API ถูกเรียกภายใต้ frontend อื่นจนกลายเป็นการขโมยข้อมูล เช่น กรณีที่ผู้ใช้ล็อกอินกับบริการจริงอยู่ แต่กำลังอยู่บน g00gle.com และทุกคำขออาจถูกโจมตีแบบ man-in-the-middle ได้

    • ที่จริงต้องบอกว่าตรงกันข้าม ปัญหาด้านความปลอดภัยแบบนี้ถูกป้องกันโดย SOP และ CORS เป็นกลไกที่ทำให้ SOP ผ่อนคลายลง เพื่อเปิดทางให้แอปพลิเคชันที่ซับซ้อนกว่าสามารถทำงานร่วมกันได้
  • ฉันก็เป็นหนึ่งในคนแบบนั้นเหมือนกัน CORS เป็นหัวข้อที่ต้องกลับมาเรียนใหม่เป็นระยะ และก็ลืมอยู่เรื่อย เลยไม่ค่อยอยู่ในหัว
    น่าจะเพราะเป็น backend developer เลยแทบไม่ค่อยเจอปัญหา CORS ของที่ไม่ได้ใช้ทุกวันก็มักลืมได้ง่าย

    • ประสบการณ์นักพัฒนากับ CORS และ CSP นั้นแย่มาก เพราะเบราว์เซอร์ไม่ค่อยบอกให้ชัดว่าปัญหาเริ่มจากตรงไหน
      ในโลกปกติ ข้อความผิดพลาดควรมีคำใบ้อย่าง “response header” หรือ “meta tag” อยู่ด้วย แต่ดูเหมือนบริษัทผู้พัฒนาเบราว์เซอร์รายใหญ่จะจ้างคนที่ชอบเขียนข้อความลึกลับมาใช้ Chrome คำว่า “requested resource” ยังถือว่าดีกว่าเจ้าอื่น แต่ก็ยังเหมือนรหัสลับอยู่ดี
      ข้อความที่ดีกว่าควรเป็นประมาณว่า resource จาก https://bank.com ไม่อนุญาตคำขอข้าม origin เพราะไม่มี CORS header หรือ origin ปัจจุบันไม่ได้อยู่ในรายการที่ CORS อนุญาต และควรแสดง preflight request ใน network tab พร้อมลิงก์ไป MDN ด้วย ส่วน CSP ก็ควรบอกว่าดึง resource ไม่ได้เพราะ CSP header ของหน้านี้ และเชื่อมไปยัง page request header หรือ meta tag ใน inspector ด้วยจะดีกว่า
    • ปัญหาใหญ่ที่สุดของ CORS คือ error ส่วนใหญ่ดูเหมือนเป็นปัญหาฝั่ง frontend โดยเฉพาะ ปัญหาของเบราว์เซอร์ แต่สิ่งที่ต้องแก้จริงๆ กลับอยู่ที่ backend
    • ฉันก็รู้สึกคล้ายกัน หลายครั้งที่ต้องจัดการกับ CORS เป็นสถานการณ์แบบ “ต้องดึงอะไรบางอย่างจากเซิร์ฟเวอร์นี้ แต่เปลี่ยน CORS หรือ CSP ของเซิร์ฟเวอร์ไม่ได้” ซึ่งถ้าพูดในภาษาความปลอดภัยก็คือ “มีระบบความปลอดภัยอยู่ แต่ต้องหาทางอ้อมมัน”
      สุดท้ายแล้วมักอาศัยสมมติฐานว่าเซิร์ฟเวอร์จะถูกเข้าถึงผ่านคำขอจากเบราว์เซอร์ที่ไม่ถูกดัดแปลงเท่านั้น ช่องโหว่ของ Zoom ก็เกิดขึ้นเพราะฝั่งไคลเอนต์สามารถหลบเลี่ยง CORS และ CSP ได้ง่ายเกินไป และแม้ Zoom จะผิด แย่ และขี้เกียจจริง แต่ก็รู้สึกว่าชุมชนที่ยังคงยึดโมเดลแบบนี้ต่อไปก็มีส่วนรับผิดชอบเช่นกัน
  • ฉันเข้าใจว่า same-origin policy ป้องกันไม่ให้เบราว์เซอร์รันสคริปต์อันตรายแล้วขโมยข้อมูลออกไปได้อย่างไร และก็เข้าใจด้วยว่าเซิร์ฟเวอร์สามารถประกาศความไว้วางใจต่อ origin เพิ่มเติมเพื่อผ่อนคลาย SOP ได้ผ่านเฮดเดอร์ Access-Control-Allow-Origin
    ถึงอย่างนั้นก็ยังไม่เข้าใจจุดประสงค์ของเฮดเดอร์ Access-Control-Allow-Headers มันไม่ได้ดูเหมือนช่วยเพิ่มความปลอดภัยของเบราว์เซอร์ และยิ่งไม่ใช่ความปลอดภัยของเซิร์ฟเวอร์ เลยสงสัยว่านักออกแบบโปรโตคอลใส่มาเพื่อ “ความครบถ้วนสมบูรณ์” หรือเปล่า เกี่ยวข้องกับ: https://stackoverflow.com/questions/17992042