1 คะแนน โดย GN⁺ 2024-09-13 | 1 ความคิดเห็น | แชร์ทาง WhatsApp
  • การตรวจสอบแบ็กเอนด์ของแอปเดตบนมือถือ Feeld พบช่องโหว่ 8 รายการ เช่น การเปิดเผยโปรไฟล์ การอ่าน·แก้ไขข้อความ และการเข้าถึงไฟล์แนบในแชต โดยทุกรายการยกเว้นรายการแรกเข้าข่าย Broken Access Control ใน OWASP Top 10
  • ผู้ใช้พื้นฐานเห็นข้อมูลได้จำกัดบนหน้าจอแอป แต่เมื่อดู response ผ่านพร็อกซี จะได้รับ ข้อมูลระดับพรีเมียม เช่น อายุ ระยะทาง รูปโปรไฟล์ และ streamUserId ของผู้ใช้ที่กด “Like” ให้
  • ช่องโหว่หลายรายการเกิดจากการนำ identifier เช่น streamUserId, profileId, messageId, channelID ที่ได้จาก response ของ API อื่นไปใส่เป็นพารามิเตอร์ในคำขอ ทำให้ขอบเขตการเข้าถึงขยายไปถึงข้อความ·แมตช์·โปรไฟล์·ไลก์ของผู้อื่น รวมถึงการส่งข้อความในแชต
  • พบปัญหากับไฟล์แนบในแชตทุกประเภท ได้แก่ รูปภาพปกติ รูปภาพจำกัดเวลา 5–15 วินาที วิดีโอปกติ และวิดีโอเล่นได้ครั้งเดียว โดย URL ของ Cloudinary·Stream CDN บางส่วนสามารถ เข้าถึงได้โดยไม่ต้องยืนยันตัวตน
  • FORTBRIDGE เปิดเผยประเด็นต่อ Feeld เมื่อวันที่ 8 มีนาคม 2024 และหลังจาก Feeld ขอเลื่อนการเผยแพร่หลายครั้ง Feeld ตอบว่าได้ปรับใช้การเปลี่ยนแปลงเพื่อลดผลกระทบของรายการที่เหลือเมื่อวันที่ 16 สิงหาคม 2024 ส่วนบล็อกเผยแพร่เมื่อวันที่ 10 กันยายน 2024

ขอบเขตช่องโหว่ที่พบใน Feeld

  • เป้าหมายคือแอปเดตบนมือถือ Feeld ซึ่งคล้ายกับ Tinder และ Bumble และมีตัวกรองตามระยะทาง·อายุ·เพศ·คู่รัก·ตำแหน่งที่ตั้ง
  • ผู้ใช้พรีเมียมสามารถค้นหาตามประเภท kink, สถานการณ์ threesome/group และประเภทความสัมพันธ์ที่สนใจได้ด้วย
  • ช่องโหว่ที่พบในการตรวจสอบความปลอดภัยมี 8 รายการ
    • เปิดเผยข้อมูลโปรไฟล์ให้ผู้ใช้ที่ไม่ใช่พรีเมียม
    • อ่านข้อความของผู้อื่น
    • เข้าถึงไฟล์แนบรูปภาพ·วิดีโอในแชตโดยไม่ต้องยืนยันตัวตน
    • ลบ·กู้คืน·แก้ไขข้อความของผู้อื่น
    • อัปเดตข้อมูลโปรไฟล์ของผู้อื่น
    • รับ ‘Like’ จากโปรไฟล์ผู้ใช้ใดก็ได้
    • ส่งข้อความไปยังแชตของผู้อื่น
    • ดูแมตช์ของผู้อื่น
  • ประเด็นทั้งหมดยกเว้นรายการแรกจัดอยู่ในหมวด Broken Access Control ของ OWASP Top 10

ข้อมูลโปรไฟล์ที่เปิดเผยต่อผู้ใช้ที่ไม่ใช่พรีเมียม

  • เมื่อผู้ใช้พื้นฐานดูผู้ใช้ที่กดถูกใจตนเองในเมนู Likes ของแอป จะแสดงเพียงชื่อและรูปภาพเบลอๆ
  • หากดักจับ request และ response ด้วยเครื่องมือพร็อกซีอย่าง Burp จะพบว่าใน response มีข้อมูลระดับเดียวกับผู้ใช้พรีเมียมรวมอยู่
    • อายุ
    • ระยะทาง
    • รูปโปรไฟล์ทั้งหมด
    • streamUserId
  • รูปโปรไฟล์ถูกเก็บไว้ที่ res.cloudinary.com และสามารถเข้าถึงได้โดยไม่ต้องยืนยันตัวตน
  • streamUserId ที่ได้จาก response สามารถนำไปใช้กับช่องโหว่การอ่านข้อความของผู้อื่นในภายหลังได้

ปัญหาการควบคุมการเข้าถึงข้อความและแมตช์

  • หากต้องการอ่านข้อความของผู้อื่น จำเป็นต้องมี streamUserId ของเหยื่อ และค่านี้รั่วไหลในคำขอ API หลายรายการ
  • ตัวอย่าง flow คือการได้ streamUserId ของผู้ใช้เป้าหมายจาก response ของคำขอ GraphQL DiscoverProfiles แล้วนำค่านั้นไปใส่ในเงื่อนไข member ของคำขอช่องแชต
  • เมื่อค้นหา "text" ใน response จะสามารถดูจำนวนและเนื้อหาข้อความที่เหยื่อรับส่งได้
  • ด้วยวิธีเข้าถึงแบบเดียวกัน ยังสามารถได้ messageId ที่แนบกับแต่ละข้อความ และค่านี้ใช้สำหรับลบ·กู้คืน·แก้ไขข้อความ
  • หากเปลี่ยนพารามิเตอร์ profileId ที่มีช่องโหว่ใน ChatListQuery จะสามารถดูแมตช์ของผู้ใช้อื่นได้
    • ข้อมูลที่ตรวจสอบได้ประกอบด้วย imaginaryName, อายุ, รูปภาพ, เพศ, sexuality, status และวันเกิด

การเข้าถึงไฟล์แนบในแชตโดยไม่ต้องยืนยันตัวตน

  • ไฟล์แนบที่แชร์ในแชตแบ่งเป็นรูปภาพและวิดีโอ
    • รูปภาพมีทั้งรูปภาพปกติที่เปิดดูได้ หรือรูปภาพจำกัดเวลา 5–15 วินาที
    • วิดีโอมีทั้งวิดีโอปกติที่เล่นได้ หรือวิดีโอเล่นได้ครั้งเดียว
  • รูปภาพปกติถูกอัปโหลดจากแอป Feeld ไปยัง api.cloudinary.com และ response จะส่งคืน photo_id
    • จากนั้นรูปภาพจะถูกคัดลอกไปยัง feeld.co และให้บริการแก่ผู้ใช้ที่ยืนยันตัวตนแล้ว
    • ใช้ path ในรูปแบบ cdn/chat-attachment/<receiver_profileId>/<photo_id> หรือ <sender_profileId>/<photo_id>
    • ส่วน profileId ใน path สามารถย่อให้เป็นสตริงสุ่มอย่างน้อย 1 ตัวอักษรก็ยังส่งคืนรูปภาพให้ผู้ใช้ที่ยืนยันตัวตนแล้ว
    • path ที่เติม /v1/ ไว้ข้างหน้าจะส่งคืน URL รูปภาพต้นฉบับที่เก็บบน Cloudinary และ URL ดังกล่าวเข้าถึงได้โดยไม่ต้องยืนยันตัวตน
  • รูปภาพจำกัดเวลาใช้พารามิเตอร์เพิ่มเติม เช่น visibilityMilliseconds:15000 ตอนอัปโหลด
    • endpoint สำหรับผู้รับ หลังจากเข้าถึงแล้ว 5–15 วินาที รูปภาพจะถูกลบและเข้าถึงไม่ได้อีก
    • endpoint ที่ใช้ profileId ของผู้อัปโหลดยังคงส่งคืนรูปภาพให้ผู้ใช้ที่ยืนยันตัวตนแล้วต่อไป แม้จะผ่านไป 5–15 วินาทีแล้ว
    • path /v1/ จะส่งคืน Cloudinary URL และ URL ดังกล่าวเข้าถึงได้โดยไม่ต้องยืนยันตัวตน
  • สำหรับวิดีโอ ทั้งวิดีโอปกติและวิดีโอเล่นได้ครั้งเดียวมี URL รวมอยู่ในข้อความแชต
    • วิดีโอปกติถูกอัปโหลดไปที่ us-east.stream-io-cdn.com
    • วิดีโอเล่นได้ครั้งเดียวใช้ flow การอัปโหลดฝั่ง chat.stream-io-api.com
    • หากผู้โจมตีได้ URL จากช่องโหว่การอ่านข้อความก่อนหน้า แล้วเปลี่ยน u0026 เป็น & ก็สามารถดูได้โดยไม่ต้องยืนยันตัวตน
  • วิดีโอเล่นได้ครั้งเดียวสามารถเล่นซ้ำได้สำหรับผู้โจมตี แต่ในแอปของผู้รับจะแสดงว่า video expired หลังจากดูครั้งเดียว

การดัดแปลงข้อความ การเปลี่ยนโปรไฟล์ และการปลอมไลก์

  • ที่ endpoint chat.stream-io-api.com/messages/<messageId> สามารถใช้เมธอด DELETE และ PUT เพื่อจัดการข้อความของผู้อื่นได้
  • ข้อความที่ถูกลบจะแสดงในแชตว่า This message was deleted แต่หากผู้โจมตีเรียกคำขอ DELETE เดิม จะสามารถได้ข้อความต้นฉบับกลับมา
  • ผู้โจมตีสามารถแก้ไขข้อความโดยใช้ messageId ได้ แม้จะไม่ใช่ผู้เข้าร่วมแชต
    • เมื่อเหยื่อกดการแจ้งเตือน จะเห็นข้อความที่ถูกแก้ไข
    • ใต้ข้อความมีเครื่องหมาย edited แต่ไม่แสดงว่าใครเป็นผู้แก้ไข
    • ชื่อบัญชีไม่เป็นเอกลักษณ์และสามารถแก้ไขได้
  • หากเปลี่ยนพารามิเตอร์ id ที่มีช่องโหว่ในคำขอ GraphQL ProfileUpdate เป็น ID ของเหยื่อ จะสามารถอัปเดต ข้อมูลโปรไฟล์ เช่น ชื่อ, sexuality, อายุ, bio ได้
  • ในคำขอ GraphQL ProfileLike ขณะล็อกอินด้วย profile#1 สามารถทำให้ดูเหมือนว่า profile#2 ส่ง ‘Like’ ไปยัง profile#3 ได้
    • ในตัวอย่าง ส่ง Like จากโปรไฟล์ใดก็ได้มายังโปรไฟล์ของตนเอง แล้ว Like นั้นจะแสดงในรายการ Likes ของบัญชีพรีเมียม

การส่งข้อความไปยังแชตของผู้อื่น

  • ผู้โจมตีสามารถส่งข้อความไปยังแชตของคนอื่นได้ แม้จะไม่ใช่ผู้เข้าร่วมแชต
  • ค่าที่ต้องใช้คือ channelID ซึ่งได้จากช่องโหว่การอ่านข้อความก่อนหน้า
  • เมื่อส่งคำขอ POST ไปยัง path channels/messaging/<channelID>/message ข้อความจะถูกเพิ่มเข้าไปใน channel นั้น
  • เหยื่อจะได้รับการแจ้งเตือนและสามารถตรวจสอบข้อความได้
  • ระบบแสดงว่าการแจ้งเตือนมาจากชื่อของผู้โจมตี แต่ผู้โจมตีสามารถเปลี่ยนชื่อโปรไฟล์ได้ และชื่อก็ไม่เป็นเอกลักษณ์

ไทม์ไลน์การเปิดเผย

  • วันที่ 8 มีนาคม 2024 FORTBRIDGE เปิดเผยประเด็นทั้งหมดต่อ Feeld
  • วันเดียวกัน Feeld ขอข้อมูลบัญชีที่ใช้ในการทดสอบ
  • วันที่ 2 เมษายน 2024 FORTBRIDGE ขออัปเดต และ Feeld ระบุว่ากำลังตรวจสอบ พร้อมขอให้ชะลอการเผยแพร่
  • วันที่ 28 พฤษภาคม 2024 Feeld ได้ปล่อยการแก้ไขหลายรายการ และขอเลื่อนสูงสุด 2 สัปดาห์เพื่อตรวจสอบว่ารายการที่พบได้รับการแก้ไขแล้วหรือไม่
  • วันที่ 8 มิถุนายน 2024 ครบ 3 เดือนนับจากอีเมลเปิดเผยครั้งแรก
  • วันที่ 15 กรกฎาคม 2024 Feeld ตอบว่าบางประเด็นต้องการการแก้ไขที่ซับซ้อนกว่า
  • วันที่ 4 สิงหาคม 2024 Feeld ขอให้ชะลอการเผยแพร่จนกว่าจะแก้ไขรายการที่เหลือ
  • วันที่ 16 สิงหาคม 2024 Feeld ตอบว่าได้ปรับใช้การเปลี่ยนแปลงเพื่อลดผลกระทบของรายการที่พบที่เหลือแล้ว
  • วันที่ 8 กันยายน 2024 ครบ 6 เดือนนับจากการเปิดเผยครั้งแรก
  • วันที่ 10 กันยายน 2024 บล็อกถูกเผยแพร่
  • เดือนสิงหาคม 2025 งานวิจัยนี้ถูกนำเสนอที่ DEF CON 33

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

 
GN⁺ 2024-09-13
ความคิดเห็นจาก Hacker News
  • ดูเหมือนว่า การตรวจสอบสิทธิ์ จะถูกทำไว้เฉพาะฝั่งฟรอนต์เอนด์เท่านั้น และไม่ใช่แค่ endpoint หนึ่งหรือสองจุด แต่เหมือนเป็นแทบทั้งระบบ
    ในเชิงแนวคิด นี่เป็นข้อผิดพลาดที่หลีกเลี่ยงได้ง่าย แต่ผมเห็นข้อผิดพลาดคล้าย ๆ กันบ่อยเสียจนไม่อยากยอมรับ
    วิธีแก้แบบ “ตรวจสอบสิทธิ์ทั้งหมดที่แบ็กเอนด์” ให้ความรู้สึกคล้ายกับกรณีบัฟเฟอร์โอเวอร์โฟลว์ที่ว่า “ใส่การตรวจสอบขอบเขตทุกที่” ทั้งคอมมูนิตี้รู้ว่าควรทำอะไร แต่การทำให้ทุกคนใช้มันอย่างสม่ำเสมอไม่ใช่เรื่องง่าย

    • ผมคิดว่าสองเรื่องนั้นไม่เหมือนกัน การตรวจสอบบัฟเฟอร์โอเวอร์โฟลว์ เป็นรายละเอียดการติดตั้งใช้งานและภาษาในระดับที่เฉพาะเจาะจงมาก และเกิดขึ้นได้ทุกที่ในโค้ดเบส
      ขณะที่การตรวจสอบสิทธิ์เกิดขึ้นที่ boundary เฉพาะ และเกี่ยวข้องกับวิธีออกแบบแอปพลิเคชัน ทุกครั้งที่ผมมีอิทธิพลต่อวิธีพัฒนาโปรเจกต์ ผมยืนกรานให้แยกการพัฒนา backend API ออกจากโค้ด frontend client อย่างชัดเจน จากประสบการณ์ วิธีนี้ทำให้หลีกเลี่ยงและทดสอบปัญหาแบบนี้ได้ง่ายกว่ามาก และยังได้ API สำหรับนักพัฒนา “ฟรี ๆ” ด้วย พูดตรง ๆ นั่นคือเหตุผลหลักที่ผมชอบแนวทางนี้
    • ถ้าสับสนเรื่องนี้ได้ ก็ไม่ควรไปแตะ โค้ดฝั่งเซิร์ฟเวอร์
    • เคยจับได้ว่านักพัฒนาเว็บคนหนึ่งทำ การยืนยันตัวตนฝั่งฟรอนต์เอนด์ ด้วยกล่องโต้ตอบ JavaScript ธรรมดา เขาใส่รหัสผ่านไว้ใน JS แล้วเปรียบเทียบแบบง่าย ๆ
      ที่รู้ก็เพราะเจ้าของบัญชี lamp ติดต่อมาว่าข้อมูลของตัวเองหายไปหมดกะทันหัน ดู log แล้วพบว่า Google Bot คลิกลิงก์ “Delete” ทั้งหมดในหน้าจัดการภายใน ที่เกิดขึ้นได้เพราะ JavaScript เป็นแบบ opt-in ผมโทรไปอธิบายกับนักพัฒนาว่าเขาทำอะไรลงไป และวันนั้นผมเสียความเชื่อมั่นในคนฝั่งเว็บไปมาก
    • ผมคิดว่าถ้าใช้ “DB API อัตโนมัติ” ในแบ็กเอนด์ เรื่องแบบนี้เกิดขึ้นได้ง่ายมาก ตัวอย่างเช่นการตั้งค่า GraphQL อัตโนมัติบางแบบ
      ทุกครั้งที่เห็นผมจะทำเครื่องหมายไว้ แต่ก็เป็นห่วงมาก เพราะบางกรณีมีการคิดถึงขอบเขตของ client API น้อยเกินไป
    • ในแอปมือถือ น่าเสียดายที่พบได้ค่อนข้างบ่อย แนวคิดคือ “ผู้ใช้จะไปส่องแอปมือถือละเอียดขนาดนั้นเหรอ?”
      อยากโทษ junior, no-code, หรือฝั่งโค้ดจาก AI อยู่เหมือนกัน แต่ผมก็ขี้เกียจพอ ๆ กับพวกเขา เลยได้แต่ส่ายหัวแล้วปล่อยผ่าน
  • นี่เป็นเหตุผลที่ดีมากที่จะไม่ใส่ ข้อมูลส่วนบุคคล ที่ถูกต้อง เช่น วันเดือนปีเกิด
    โดยเฉพาะแอปเดตที่ดูเหมือนจะขอข้อมูลแบบนี้ แต่ไม่ควรให้ ควรใส่ค่าที่ต่างจากวันเกิดจริงสักราว ๆ หนึ่งปี
    แอปเดตนี้ไม่ได้เป็นที่รู้จักมากนัก แต่เจาะกลุ่มผู้ใช้เควียร์และคนที่มีรสนิยมอื่น ๆ เช่น BDSM หรือ group sex ในหลายภูมิภาคของโลก ข้อมูลแบบนี้ย่อมอ่อนไหวมากอย่างไม่ต้องสงสัย

  • สัปดาห์นี้มีข่าวในสื่อเยอะเพราะทำเงินได้ดี
    https://www.theguardian.com/technology/article/2024/sep/08/t...

    • หลายคนได้เห็นกันมามากแล้วว่า ทุกวันนี้ การสร้างสิ่งแย่ ๆ ดูจะทำเงินได้มากกว่าการสร้างสิ่งดี ๆ มาก
    • ควรให้ The Guardian เห็นเรื่องนี้
  • เมื่อคิดถึงหมวดหมู่ของแอปแล้ว นี่เป็นความล้มเหลวในระดับ ความประมาททางอาญา

    • ผมนี่แหละเคยเป็นผู้รับเหมาถูก ๆ แบบนั้น เจ้านายไม่สนใจอะไรเลยนอกจากกำหนดส่งและบั๊กที่ reviewer ฝั่งลูกค้ามองเห็น
      ผมคิดว่าสิ่งเดียวที่จะยับยั้งได้คือการขู่จำคุกในสหรัฐฯ และ EU, ประกันภัยที่เกี่ยวกับข้อมูล และต้นทุนประกันข้อมูล ถ้ารูปนั้นไม่ใช่แบบที่เอาไปลง LinkedIn ได้ ก็ต้องจ่ายราคาแพงหูฉี่
      แน่นอนว่าแรงจูงใจไม่ควรส่งเสริมการปกปิด
    • ไม่ได้ล้อเล่นสินะ ช่องโหว่ แบบนี้ ต่อให้เมื่อ 10 ปีก่อนก็ยังน่าอาย
  • วงการเดตออนไลน์เละเทะไปหมด มีบริษัทแค่ 2–3 แห่งที่พอจะเรียกว่ามีบริการที่เป็นประโยชน์ และบริษัทเหล่านั้นก็ชั่วร้าย หรือไร้ความสามารถ หรือทั้งสองอย่าง
    ตอนนี้เราอาจต้องการอะไรอย่าง บริการเดตแบบโอเพนซอร์สที่เป็น federated แล้วก็ได้ อย่างน้อยต้องเป็นสิ่งที่ไม่ขายข้อมูล ไม่ทำรูปนู้ดรั่ว และไม่ทำให้ผู้ใช้ถูกทำร้าย ถูกข่มขืน หรือถูกฆ่า พูดง่ายกว่าทำแน่นอน

    • ผมวางแผนเรื่องแบบนั้นมาหลายปีแล้ว แต่ไม่มีโดปามีนเหลือพอจะสร้างควบคู่กับงานประจำ
      ActivityPub เองก็มีโครงสร้างที่ทำให้เป็นไปได้ผ่านการเผยแพร่ระเบียน Person โดยเฉพาะถ้าให้ความสำคัญกับความต้องการของคนที่ไม่ใช่ความสัมพันธ์แบบผัวเดียวเมียเดียว คนที่ไม่ใช่รักต่างเพศ และคนที่ไม่สอดคล้องกับกรอบเพศสภาพ ยังมีพื้นที่ให้สร้างนวัตกรรมได้มหาศาล
      แต่แอปเดตเป็นสาขาที่เข้ายากจริง ๆ จะให้มีประโยชน์ต้องมีฐานผู้ใช้สะสมในพื้นที่หนึ่ง ๆ และพอ monetization เข้ามา แอปก็จะมีประโยชน์น้อยลงอย่างเลี่ยงไม่ได้ มีเหตุผลที่ okcupid พังหลังจากเลิกมีลักษณะกึ่งไม่แสวงหากำไร
      แล้วก็ยังมี ปัญหาการมอดเดอเรชัน ด้วย
    • ผมรู้สึกว่ารูปนู้ดควรคงอยู่ในรูปแบบอนาล็อก แบบนั้นคุณควบคุมการเผยแพร่ได้เกือบสมบูรณ์และเด็ดขาด
      ถ้าอยากแปลงรูปแบบอนาล็อกเป็นสำเนาดิจิทัล นั่นเป็นสิทธิของแต่ละคน แต่ต้องรู้ว่าไม่มีระบบใดปลอดภัยพอที่จะป้องกันการรั่วไหลและการเผยแพร่ได้ในที่สุด และในอนาคตก็จะยังเป็นแบบนั้น
      โดยเฉพาะคนหนุ่มสาวมักไม่คำนึงถึงผลลัพธ์และความอับอายที่อาจเกิดขึ้นและมีแนวโน้มสูงว่าจะเกิดขึ้นในระยะยาว การให้ฟีเจอร์แบบนั้นก็เท่ากับเชื้อเชิญผลลัพธ์ด้านลบเท่านั้น
  • แย่มากจริง ๆ เห็นชัดว่า ไม่ได้คิดเรื่องความปลอดภัยเลย
    ผมเป็นนักพัฒนาเกม และบริษัทนี้ทุ่มเทให้การรักษาความปลอดภัยของผู้ใช้น้อยกว่าที่พวกเราทุ่มเทให้เกมยุติธรรมเสียอีก ควรถูกฟ้องจนพัง

    • ดูเหมือนไม่ได้คิดเรื่องความปลอดภัยอย่างเดียว แต่ไม่ได้คิดอะไรเลยด้วยซ้ำ
      ก่อนจะรู้ว่าแอปเต็มไปด้วยบั๊ก ผมก็ประหลาดใจมากแล้วที่ส่วนความสนใจไม่ให้บริบทอะไรเลย เช่น แทบทุกคนมี Domination หรือ Submission เป็นความสนใจ แต่ไม่มีบริบทเลยว่าต้องการบทบาทไหน การไม่รู้ว่าสิ่งนี้ผิดพื้นฐานแค่ไหนในฉากนั้น แปลว่าโดยรวมแล้วไม่รู้อะไรเลย
    • ต้องพิจารณาด้วยว่าโปรไฟล์ในแอปเดตโดยหลักการแล้วทุกคนเข้าถึงได้ เปิดแอปขึ้นมาก็เห็นโปรไฟล์ ไม่มีอะไรอย่าง ACL
      ข้อความและรูปส่วนตัวเป็นอีกเรื่องหนึ่ง
  • ถ้าพูดแบบยั่ว ๆ หน่อย นี่คือ ปัญหาของ GraphQL
    GraphQL ทำให้ frontend สามารถ query ข้อมูลได้ ฟังดูเจ๋ง แต่จากมุมมองของ backend แล้วมันค่อนข้างทึบมาก และมักถูก implement ด้วยไลบรารี third-party ที่ไม่รู้อะไรเลยเกี่ยวกับ access control
    ถ้าคุณจะไม่ implement access control ไว้ที่ตัว database เอง การแกะ query ของ GraphQL ในโค้ด backend เพื่อหาว่าควรคืน record ไหนหรือจำกัด record ไหนนั้นทำได้ยากมาก การทำใน database ไม่ได้แย่ที่สุด และแน่นอนว่าดีกว่าทำที่ frontend
    ถ้าจะ implement access control ที่ถูกต้องใน backend ก็ต้องเข้าใจ query, รู้ schema ของ database แล้วสร้าง model/class/function ฯลฯ ที่ตัดสินได้ว่า “ถ้า user_id เป็น XXX ในบริบทนี้จะดูรูปนี้ได้/ไม่ได้” ใน GraphQL การ implement ที่ frontend ง่ายกว่ามาก ดังนั้นชัดเจนว่าพวกเขาเลือกทำแบบนั้น
    ไม่ได้หมายความว่า implementation ของ GraphQL ดี หรือปัญหาเป็นของ GraphQL ทั้งหมด แต่หมายความว่า GraphQL พยายามทำให้ backend ไม่จำเป็นต้องเข้าใจ query จึงทำให้สถานการณ์ด้านความปลอดภัยที่ซับซ้อนแบบนี้ยากขึ้น และทำให้พลาดแบบนี้ได้ง่ายขึ้น
    [0] เช่น รูปบางรูปอาจเข้าถึงแบบสาธารณะได้บนโปรไฟล์ผู้ใช้ แต่เห็นได้เฉพาะคนที่ match กันเท่านั้น หรือเห็นได้เฉพาะในบริบทของแชตเท่านั้น (ยกเว้น group chat) หรือผู้ใช้ที่ถูกบล็อกอาจเข้าถึงไม่ได้ตลอดเวลา แค่กรณีเดียวนี้ก็สร้าง edge case ซับซ้อนได้เต็มไปหมด

    • ค่อนข้างง่ายนะ ปฏิบัติกับ resolver แต่ละตัวที่ดึงข้อมูลเหมือน REST endpoint แล้วป้องกันมันไว้ จากนั้นมี allowlist ของ query ที่เพิ่มรายการระหว่าง CI build ก็พอ
      ไม่จำเป็นต้องไปยุ่งกับ AST หรือเข้าใจบริบทของ query ส่วนที่เหลือ ใน resolver ที่ดึงรูป ก็แค่ตอบคำถามว่า “ผู้ใช้ ABC ดูรูปของผู้ใช้ XYZ ได้ไหม?” ถ้าไม่มีประสิทธิภาพพอ ก็ preload ข้อมูลบางส่วนหรือใช้ dataloader ได้
      แต่ถ้าคุณใช้ไลบรารีวิเศษที่แปลง GraphQL เป็น SQL ให้ เรื่องก็จะอีกแบบ
    • ใน GraphQL ต้องกำหนดสิทธิ์การเข้าถึงแยกตาม attribute หรือ precompile query แล้วใส่ไว้ใน allowlist นอกเหนือจากนั้นข้อมูลจะรั่วหมด
      https://hasura.io/docs/2.0/security/allow-list/
    • ไลบรารี GraphQL third-party ที่พอใช้ได้ควรต้อง implement ACL ในรูปแบบใดรูปแบบหนึ่ง ตัวที่ได้รับความนิยมที่สุดก็ดูเหมือนจะทำแบบนั้น [1] [2]
      แนวคิดง่าย ๆ คือ implement authorization ไว้ใน data model ให้ GraphQL delegate get และ list ไปยัง resource model ที่สามารถ implement authorization ตามบริบทของ request ได้
      [1] https://www.apollographql.com/docs/apollo-server/security/au...
      [2] https://docs.graphene-python.org/projects/django/en/latest/a...
    • ตอนใช้ HotChocolate ไม่เจอปัญหานี้ สามารถใส่ กฎ authorization ให้กับ entity หรือ attribute ของ entity ได้ง่าย ๆ และมันจัดการให้อัตโนมัติ ใช้กับ mutation ได้ด้วย
  • เป็นการเปิดเผยที่ มีความรับผิดชอบและคำนึงถึงผู้อื่น อย่างน่าทึ่ง

    • ในเมนู “Discover profiles” กับ screenshot รายการ like มีโปรไฟล์จริงรวมอยู่ด้วยหรือเปล่า? ถ้าใช่ ต่อให้ปิดหน้าไว้ก็ยังค่อนข้างไร้ความรับผิดชอบ
    • การกระทำไม่สอดคล้องกับคำพูด
  • ไม่ได้แปลกใจมากนัก ใช้อยู่เหมือนกัน แต่คงบอกได้ว่ามันถูกสร้างมาอย่างไร้ความสามารถพอ ๆ กับแอปธนาคารของผม อาจจะแย่กว่าด้วยซ้ำ และแทบจะใช้งานไม่ค่อยได้
    ไม่รู้เลยว่าทำออกมาแบบนี้ได้ยังไง

    • ตอนผมใช้ก็แย่มากเหมือนกัน ถ้าไม่ใช่ memory leak แปลก ๆ หรือปัญหาความเป็นส่วนตัว ก็เป็น UX ที่ implement ได้ห่วยสุด ๆ
      ดูแอปนี้กับ Fetlife แล้ว จะเห็นว่าชุมชนเหล่านี้มีปัญหาใหญ่ตรงที่ยังคงอยู่กับแอปแรกที่โผล่มา โดยไม่สนใจคุณภาพ
    • ตอนผมใช้ community ดี แต่ตัวแอปไม่เคยถูกเขียนมาอย่างถูกต้องเลย
      แล้วไม่นานมานี้พวกเขาก็มี flag day ที่ปล่อยแอปใหม่และเซิร์ฟเวอร์ใหม่ให้ทุกคนพร้อมกันทีเดียว คนส่วนใหญ่ถึงขั้น login ไม่ได้ด้วยซ้ำ คนที่ login ได้ ถ้าเป็นลูกค้าแบบจ่ายเงินก็เสียสิทธิ์ premium ไป และเกิดปัญหาอย่าง like กับ chat หายไป ผมสุดท้ายก็ login ไม่ได้ และเลิกใช้แอปไปตอนนั้น
  • บอกตรง ๆ ว่าแปลกใจที่นักวิจัยอดทนรอการเปิดเผยได้นานขนาดนี้
    ถ้าให้เวลา startup ห่วย ๆ 6 เดือนเพื่อปิด ช่องโหว่ความเป็นส่วนตัว ที่ร้ายแรงขนาดนี้ พวกเขาก็จะยังคงใช้สิทธิพิเศษในการเก็บข้อมูลแบบนี้ในทางที่ผิดตั้งแต่แรกต่อไป ผมคิดว่าควรให้แค่ 2 เดือนแล้วเปิดเผยได้เลย พวกเขาต้องเรียนรู้ว่าไม่ควรเอาข้อมูลส่วนตัวของผู้คนมาเล่นเป็นเกมทอยลูกเต๋า