การขาดการตรวจสอบความปลอดภัยบน GET collection endpoint ทำให้ใครก็ตามที่มีบัญชี CoopCycle พื้นฐานสามารถดึงสมุดที่อยู่ทั้งหมดของทุกร้านค้าใน shared instance ได้ ซึ่งเป็นการเปิดเผยชื่อ ที่อยู่ และรหัสไปรษณีย์ของลูกค้าจำนวนมหาศาล ช่องโหว่นี้ได้รับการแก้ไขแล้วภายในสองวัน และขอให้ผู้ใช้งานรีบอัปเกรดเป็นเวอร์ชันล่าสุดที่ปล่อยออกมา

สาเหตุของการรั่วไหล

CoopCycle – แพลตฟอร์มโลจิสติกส์แบบโอเพนซอร์สที่ใช้งานโดยสหกรณ์จัดส่งอาหาร – กำหนด API ของตนด้วย PHP framework ที่ชื่อว่า API Platform ใน framework นี้ แต่ละการทำงาน (POST, GET และอื่นๆ) จะต้องจับคู่กับ security expression หากไม่มีการระบุ expression ตัว framework จะรันโค้ดโดยไม่มีการตรวจสอบสิทธิ์ (authorization check) ใดๆ

นักพัฒนาได้ป้องกันคำขอ POST ที่ใช้ในการสร้างหรืออัปเดตรายการที่อยู่ของร้านค้าด้วย expression มาตรฐานคือ is_granted('edit', object) ซึ่งใช้งานได้เนื่องจากคำขอนั้นมุ่งเป้าไปที่เอนทิตีร้านค้าเพียงรายการเดียว ทำให้ framework มี "object" ที่ชัดเจนในการประเมินผล

อย่างไรก็ตาม คำขอ GET ที่อ่านทรัพยากรเดียวกันนั้นมุ่งเป้าไปที่ collection: /api/stores/{id}/addresses ซึ่ง collection ไม่มี object เดี่ยวๆ ดังนั้นจึงไม่สามารถใช้ expression is_granted('edit', object) แบบเดิมได้ และเนื่องจากนักพัฒนาไม่ได้ใส่บรรทัดการรักษาความปลอดภัยไว้ framework จึงส่งข้อมูลที่อยู่ให้กับผู้ใช้ที่ผ่านการยืนยันตัวตนทุกคน โดยไม่คำนึงถึงความเป็นเจ้าของข้อมูล (tenancy)

ใน shared instance ของ CoopCycle ผู้ใช้ที่ประสงค์ร้ายสามารถวนลูปผ่าน ID ของร้านค้า ส่งคำขอ GET ไปยัง endpoint และดึงข้อมูลที่อยู่บ้านของลูกค้าทุกคนที่จัดเก็บไว้ในระบบได้ โดยไม่จำเป็นต้องมีสิทธิ์พิเศษใดๆ นอกเหนือจากบัญชีผู้ใช้ปกติ

ทำไมบั๊กนี้ถึงยังหลุดรอดไปได้

ปัญหานี้ไม่ใช่เพียงความประมาทเลินเล่อทั่วไป โมเดลความปลอดภัยแบบประกาศ (declarative security model) ของ API Platform ขาดวิธีการที่ตรงไปตรงมาในการระบุว่า "ผู้ใช้ต้องอยู่ใน tenant เดียวกันกับแต่ละ object ใน collection" บรรทัดโค้ดที่หายไปนั้นอยู่ในจุดที่ framework ทำให้การตรวจสอบสิทธิ์มีความยุ่งยากพอดี

สิ่งที่ทำให้ปัญหาซับซ้อนขึ้นคือ ชุดทดสอบ (test suite) ของโปรเจกต์กลับระบุว่าการตอบกลับของ GET ที่มีที่อยู่ทั้งหมดนั้นเป็นพฤติกรรมที่คาดหวัง กล่าวคือ การทดสอบอัตโนมัติผ่านเพราะข้อมูลจำลอง (fixtures) ที่ใช้ในการทดสอบอนุญาตให้มีการเข้าถึงข้าม tenant ได้ ซึ่งเป็นการปกปิดช่องโหว่โดยไม่ตั้งใจ ในกรณีนี้ ชุดทดสอบที่ขึ้นสถานะสีเขียว (ผ่าน) กลับให้ความรู้สึกปลอดภัยที่ผิดพลาด

ใครได้ประโยชน์และใครเสียประโยชน์

  • ลูกค้า: ข้อมูลที่ระบุตัวตนบุคคลได้ (PII) เช่น ชื่อเต็มและที่อยู่บ้าน ถูกเปิดเผยต่อทุกคนบนแพลตฟอร์ม แม้ว่าข้อมูลจะไม่ได้ถูกโพสต์ต่อสาธารณะ แต่การรั่วไหลนี้ได้กระทบต่อความเป็นส่วนตัวของสหกรณ์หลายแห่ง
  • สหกรณ์ที่ใช้งาน CoopCycle: ความเชื่อมั่นในความสามารถของแพลตฟอร์มในการปกป้องข้อมูลของ tenant สั่นคลอน สหกรณ์ใดที่ยังไม่ได้อัปเกรดจะเผชิญกับความเสี่ยงที่จะถูกเปิดเผยข้อมูลอย่างต่อเนื่อง
  • ผู้ดูแล CoopCycle: การตอบสนองที่รวดเร็ว – การออก patch ภายในสองวันและการเพิ่ม regression tests – ช่วยจำกัดช่วงเวลาที่อาจเกิดการโจมตีและแสดงให้เห็นถึงการดูแลจัดการโอเพนซอร์สอย่างมีความรับผิดชอบ อย่างไรก็ตาม เหตุการณ์นี้เน้นย้ำถึงความจำเป็นในการมีกระบวนการตรวจสอบความปลอดภัยที่เข้มงวดขึ้น โดยเฉพาะอย่างยิ่งในส่วนที่เกี่ยวข้องกับค่าเริ่มต้นที่ขับเคลื่อนโดย framework

สิ่งที่นักพัฒนาและผู้ตรวจสอบควรระวัง

  • ความไม่สมมาตรของการทำงาน (Operation asymmetry): หากคำขอ POST (หรือการทำงานที่เปลี่ยนแปลงข้อมูลใดๆ) ในเส้นทางหนึ่งมีการป้องกันไว้ แต่คำขอ GET ที่เกี่ยวข้องกลับเปิดกว้าง ความแตกต่างนี้คือสัญญาณเตือนภัย (red flag) เพราะ POST แสดงให้เห็นถึงความตั้งใจของนักพัฒนาที่จะปกป้องทรัพยากรนั้น
  • Collection endpoints: อะไรก็ตามที่ส่งคืนรายการ (list) แทนที่จะเป็นรายการเดี่ยว มักจะอยู่นอกรูปแบบความปลอดภัยปกติ ควรตรวจสอบให้แน่ใจว่ามีการเพิ่มการตรวจสอบสิทธิ์สำหรับการอ่านข้อมูลจำนวนมาก (bulk reads) อย่างชัดเจน
  • ความสมจริงของชุดทดสอบ (Test suite realism): ตรวจสอบให้แน่ใจว่าข้อมูลจำลอง (fixtures) สะท้อนถึงขอบเขตของ tenant ในโลกความเป็นจริง การทดสอบที่ผ่านแต่กลับยืนยันว่ามีการรั่วไหลของข้อมูลข้าม tenant คือสัญญาณเตือน ไม่ใช่สัญญาณไฟเขียว

การแก้ไขและขั้นตอนต่อไป

หลังจากที่มีการรายงานช่องโหว่ ทีมหลักของ CoopCycle ได้เพิ่ม security expression ที่หายไปในการทำงานของ GET collection และได้นำ regression tests มาใช้เพื่อบังคับใช้การแยกข้อมูลตาม tenant (tenant isolation) สำหรับทั้ง endpoint แบบรายการเดี่ยวและแบบ collection โดย patch นี้ได้ถูกปล่อยออกมาในซอฟต์แวร์เวอร์ชันถัดมา

ผู้ใช้งาน CoopCycle ควร:

  1. ตรวจสอบว่ากำลังใช้งานซอฟต์แวร์เวอร์ชันล่าสุด
  2. ตรวจสอบส่วนขยายหรือปลั๊กอินที่ปรับแต่งเอง ซึ่งอาจทำให้เกิดช่องโหว่ในระดับ collection ในลักษณะเดียวกัน
  3. ทำการสแกนความปลอดภัยอีกครั้ง โดยเน้นไปที่ความไม่สมมาตรของการอ่าน/เขียน (read/write asymmetries) ในทุกเส้นทางของ API

บทสรุป

เฟรมเวิร์กที่ทำให้ความปลอดภัยเป็นแบบ Declarative อาจซ่อนช่องโหว่ที่อันตรายเอาไว้ เมื่อนักพัฒนาพึ่งพาเพียงรูปแบบ (patterns) ที่ใช้ได้ผลกับออบเจกต์เดี่ยวเท่านั้น การตรวจสอบง่ายๆ เพียงแค่ว่า—ฝั่งการอ่าน (read side) ของเอนด์พอยต์มีการป้องกัน (guard) แบบเดียวกับฝั่งการเขียน (write side) หรือไม่?—สามารถเผยให้เห็นช่องโหว่ประเภทการรั่วไหลของข้อมูลข้ามเทแนนท์ (cross-tenant leaks) ซึ่งหากไม่ตรวจสอบก็อาจจะถูกซ่อนไว้ภายใต้ชุดการทดสอบที่ผ่านฉลุย (green test suites)