08 ต.ค. 2568·อ่าน 2 นาที

การออกแบบการค้นหาแบบรวมที่คำนึงถึงสิทธิ์โดยไม่ให้ข้อมูลรั่วไหล

เรียนรู้วิธีออกแบบการค้นหาแบบรวมที่คำนึงถึงสิทธิ์ด้วยการจัดทำดัชนีที่รวดเร็วและการตรวจสอบการเข้าถึงต่อระเบียนอย่างเข้มงวด เพื่อให้ผู้ใช้ได้ผลลัพธ์อย่างรวดเร็วโดยไม่เกิดการรั่วไหล

การออกแบบการค้นหาแบบรวมที่คำนึงถึงสิทธิ์โดยไม่ให้ข้อมูลรั่วไหล

ทำไมการค้นหาแบบรวมอาจทำให้ข้อมูลรั่วไหล

การค้นหาแบบรวมมักหมายถึงกล่องค้นหาเดียวที่สแกนทั้งแอป: ลูกค้า ตั๋ว ใบแจ้งหนี้ เอกสาร ผู้ใช้ และสิ่งอื่น ๆ ที่คนทำงานด้วย มันมักขับเคลื่อนการเติมข้อความอัตโนมัติและหน้าผลลัพธ์ด่วนเพื่อให้ผู้ใช้ไปยังระเบียนได้ทันที.

การรั่วไหลเกิดขึ้นเมื่อการค้นหาคืนค่าบางอย่างที่ผู้ใช้ไม่มีสิทธิ์จะรู้ว่ามีอยู่ แม้พวกเขาจะเปิดระเบียนไม่ได้ แต่บรรทัดเดียวเช่นชื่อเรื่อง ชื่อบุคคล แท็ก หรือส่วนที่เน้นก็สามารถเปิดเผยข้อมูลที่ละเอียดอ่อนได้.

การค้นหาดูเหมือนเป็น "อ่านอย่างเดียว" ทีมมักประเมินค่าต่ำกว่าความเสี่ยง แต่การค้นหาสามารถเปิดเผยข้อมูลผ่านชื่อผลลัพธ์และตัวอย่าง ออโต้คอมพลีท ยอดรวมของผลลัพธ์ แฟคเซ็ตอย่าง "ลูกค้า (5)" และแม้แต่ความแตกต่างด้านเวลา (เช่น คำค้นบางคำเร็ว บางคำช้า).

ปัญหานี้มักปรากฏชัดทีหลัง ไม่ใช่ตั้งแต่วันแรก ตอนแรกทีมส่งมอบการค้นหาเมื่อมีเพียงบทบาทเดียว หรือเมื่อทุกคนเห็นทุกอย่างในฐานข้อมูลทดสอบ เมื่อผลิตภัณฑ์โตขึ้น คุณเพิ่มบทบาท (ซัพพอร์ต vs เซลส์, ผู้จัดการ vs เจ้าหน้าที่) และฟีเจอร์อย่างกล่องจดหมายร่วม โน้ตส่วนตัว ลูกค้าที่จำกัด และ "บัญชีของฉันเท่านั้น" หากการค้นหายังคงอาศัยสมมติฐานเก่า มันจะเริ่มแสดงเบาะแสข้ามทีมหรือข้ามลูกค้าได้

โหมดความล้มเหลวที่พบบ่อยคือการจัดทำดัชนี "ทุกอย่าง" เพื่อความเร็ว แล้วพยายามกรองผลลัพธ์ในแอปหลังการค้นหา — นั่นมักสายเกินไป เครื่องมือค้นหาตัดสินใจแล้วว่าอะไรตรงกัน และอาจเปิดเผยระเบียนที่ถูกจำกัดผ่านคำแนะนำ ยอดรวม หรือฟิลด์บางส่วน

ลองนึกภาพเจ้าหน้าที่ซัพพอร์ตที่ควรเห็นแค่ตั๋วของลูกค้าที่มอบหมายให้เขา พวกเขาพิมพ์ "Acme" และออโต้คอมพลีทแสดง "Acme - Legal escalation" หรือ "Acme breach notification" แม้การคลิกจะขึ้น "access denied" แต่แค่ชื่อเรื่องก็เป็นการรั่วไหลของข้อมูล

เป้าหมายของการค้นหาแบบรวมที่คำนึงถึงสิทธิ์พูดง่ายแต่ทำยาก: คืนค่าผลลัพธ์ที่เร็วและตรงตามบริบท ขณะเดียวกันบังคับใช้กฎการเข้าถึงเดียวกับที่คุณใช้เมื่อเปิดแต่ละระเบียน ทุกคำค้นต้องทำงานราวกับว่าผู้ใช้เห็นได้เพียงส่วนข้อมูลของตนเท่านั้น และ UI ต้องหลีกเลี่ยงการให้เบาะแสเพิ่มเติม (เช่น ยอดรวม) นอกส่วนข้อมูลนั้น

สิ่งที่คุณกำลังจัดทำดัชนีและสิ่งที่ต้องปกป้อง

การค้นหาแบบรวมดูเรียบง่ายเพราะผู้ใช้พิมพ์คำแล้วคาดหวังคำตอบ แต่เบื้องหลังคุณกำลังสร้างพื้นผิวใหม่สำหรับการเปิดเผยข้อมูล ก่อนจะเลือกดัชนีหรือฟีเจอร์ฐานข้อมูล ให้ชัดเจนสองเรื่อง: วัตถุที่คุณค้นหา (entities) และส่วนใดของวัตถุเหล่านั้นที่ละเอียดอ่อน

entity คือระเบียนใด ๆ ที่ใครบางคนอาจต้องการค้นหาอย่างรวดเร็ว ในแอปธุรกิจโดยทั่วไปรวมถึง ลูกค้า ตั๋ว ใบแจ้งหนี้ คำสั่งซื้อ และไฟล์ (หรือเมตาดาต้าของไฟล์) นอกจากนี้อาจรวมระเบียนบุคคล (ผู้ใช้ เจ้าหน้าที่) โน้ตภายใน และวัตถุระบบอย่างการเชื่อมต่อหรือคีย์ API หากมีชื่อ รหัส หรือสถานะที่ใครอาจพิมพ์ มักจะลงท้ายด้วยการถูกใส่ในการค้นหาแบบรวม

กฎต่อระเบียน vs กฎต่อเทเบิล

กฎต่อเทเบิลเป็นแบบหยาบ: คุณเข้าถึงทั้งตารางหรือไม่เข้าถึง ตัวอย่าง: เฉพาะฝ่ายการเงินสามารถเปิดหน้าบิลได้ นี่ง่ายแต่พังเมื่อคนต่างกันควรเห็นแถวต่างกันในตารางเดียวกัน

กฎต่อระเบียนตัดสินการมองเห็นเป็นแถว ๆ ตัวอย่าง: เจ้าหน้าที่ซัพพอร์ตเห็นตั๋วที่มอบหมายให้ทีมของตน ในขณะที่ผู้จัดการเห็นตั๋วทั้งหมดในภูมิภาคของตน อีกกฎทั่วไปคือความเป็นเจ้าของของผู้เช่า: ในแอปหลายผู้เช่า ผู้ใช้เห็นแค่ระเบียนที่มี customer_id = their_customer_id.

กฎต่อระเบียนมักเป็นจุดที่การค้นหารั่วไหล หากดัชนีคืนการจับคู่ก่อนที่คุณจะตรวจสิทธิ์แถว คุณก็เปิดเผยแล้วว่ามีบางอย่างอยู่

"ได้รับอนุญาตให้ดู" หมายถึงอะไรในทางปฏิบัติ

"ได้รับอนุญาต" ไม่ใช่แค่ใช่/ไม่ใช่ มันมักผสมผสานความเป็นเจ้าของ (สร้างโดยฉัน มอบหมายให้ฉัน) การเป็นสมาชิก (ทีมของฉัน แผนกของฉัน บทบาทของฉัน) ขอบเขต (ภูมิภาค หน่วยธุรกิจ โครงการ) สถานะระเบียน (เผยแพร่ ไม่ถูกเก็บถาวร) และกรณีพิเศษ (ลูกค้า VIP บันทึกทางกฎหมาย แท็กรจำกัด)

เขียนกฎเหล่านี้เป็นภาษาธรรมดาก่อน จากนั้นค่อยแปลงเป็นโมเดลข้อมูลพร้อมการตรวจสอบฝั่งเซิร์ฟเวอร์

ตัดสินใจว่าส่วนใดปลอดภัยที่จะโชว์ในตัวอย่างผลลัพธ์

ผลการค้นหามักมีตัวอย่างสั้น ๆ และตัวอย่างสามารถรั่วไหลข้อมูลได้แม้ผู้ใช้จะเปิดระเบียนไม่ได้

ค่าเริ่มต้นที่ปลอดภัยคือแสดงเฉพาะฟิลด์ขั้นต่ำที่ไม่ละเอียดอ่อนจนกว่าจะยืนยันสิทธิ์: ชื่อแสดงหรือชื่อเรื่อง (บางครั้งมาสก์), ตัวระบุสั้น ๆ (เช่น หมายเลขคำสั่งซื้อ), สถานะระดับสูง (Open, Paid, Shipped), วันที่ (สร้าง/อัปเดต) และป้ายประเภทวัตถุทั่วไป (Ticket, Invoice)

ตัวอย่างชัดเจน: ถ้ามีคนค้นหา "Acme merger" และมีตั๋วที่ถูกจำกัด การคืนค่า "Ticket: Acme merger draft - Legal" ก็เป็นการรั่วไหลแล้ว ผลลัพธ์ที่ปลอดภัยกว่าอาจเป็น "Ticket: Restricted" โดยไม่มีตัวอย่าง หรือไม่มีผลลัพธ์เลย ขึ้นกับนโยบายของคุณ

การนิยามสิ่งเหล่านี้ให้ถูกต้องตั้งแต่แรกจะทำให้การตัดสินใจในภายหลังง่ายขึ้น: จะจัดทำดัชนีอะไร จะกรองอย่างไร และยินดีเปิดเผยอะไรบ้าง

ข้อกำหนดพื้นฐานสำหรับการค้นหาที่ปลอดภัยและรวดเร็ว

คนใช้การค้นหาแบบรวมเมื่อรีบ หากช้ากว่าหนึ่งวินาที ผู้ใช้จะเริ่มไม่เชื่อถือและกลับไปกรองด้วยมือ แต่ความเร็วเป็นเพียงครึ่งงาน การค้นหาที่เร็วแต่รั่วไหลแม้ระเบียนเดียวก็แย่กว่าการไม่มีการค้นหาเลย

กฎหลักไม่ต่อรอง: บังคับใช้สิทธิ์ในเวลาค้นหา ไม่ใช่แค่ใน UI การซ่อนแถวหลังจากดึงมาแล้วสายเกินไปเพราะระบบแตะข้อมูลที่ไม่ควรถูกส่งกลับแล้ว

สิ่งนี้ใช้กับทุกอย่างรอบการค้นหา ไม่ใช่แค่รายการผลสุดท้าย คำแนะนำ ผลลัพธ์ยอดนิยม ยอดรวม และแม้แต่การตอบว่า "ไม่มีผลลัพธ์" ก็รั่วไหลได้ ออโต้คอมพลีทที่แสดง "Acme Renewal Contract" ให้คนที่เปิดไม่ได้คือการรั่วไหล แฟคเซ็ตที่บอกว่า "12 ใบแจ้งหนี้ที่ตรงกัน" เป็นการรั่วไหลหากผู้ใช้อนุญาตให้เห็นแค่ 3 แม้แต่เวลาตอบช้าสำหรับการจับคู่ที่จำกัดก็สามารถให้เบาะแสได้

การค้นหาแบบรวมที่ปลอดภัยต้องมีสี่อย่าง:

  • ความถูกต้อง: ทุกไอเท็มที่คืนค่าต้องอนุญาตสำหรับผู้ใช้นี้ สำหรับผู้เช่านี้ และสำหรับเวลานี้
  • ความเร็ว: ผลลัพธ์ คำแนะนำ และยอดรวมต้องรวดเร็วอย่างสม่ำเสมอ แม้ที่สเกลใหญ่
  • ความสอดคล้อง: เมื่อการเข้าถึงเปลี่ยน (อัปเดตบทบาท ตั๋วถูกย้าย) การค้นหาต้องเปลี่ยนอย่างรวดเร็วและคาดเดาได้
  • ความตรวจสอบได้: คุณต้องอธิบายได้ว่าทำไมไอเท็มถึงถูกส่งกลับ และบันทึกกิจกรรมการค้นหาเพื่อตรวจสอบ

เปลี่ยนมุมมอง: ถือว่าการค้นหาเป็น API ข้อมูล ไม่ใช่ฟีเจอร์ UI นั่นหมายถึงกฎการเข้าถึงเดียวกับหน้ารายการต้องใช้กับการสร้างดัชนี การประมวลผลคำค้น และทุกเอ็นด์พอยต์ที่เกี่ยวข้อง (autocomplete, recent searches, popular queries)

รูปแบบการออกแบบสามแบบที่ใช้บ่อย (และเมื่อต้องใช้แต่ละแบบ)

กล่องค้นหาสร้างง่าย แต่การค้นหาแบบรวมที่คำนึงถึงสิทธิ์ยาก เพราะดัชนีต้องการคืนผลทันที ในขณะที่แอปของคุณต้องไม่ให้ข้อมูลที่ผู้ใช้ไม่มีสิทธิ์เห็นโดยอ้อม

ด้านล่างคือสามรูปแบบที่ทีมมักใช้ บทสรุปจะช่วยให้คุณเลือกตามความซับซ้อนของกฎการเข้าถึงและความเสี่ยงที่ยอมรับได้

Approach A: จัดทำดัชนีเฉพาะฟิลด์ที่ "ปลอดภัย" แล้วค่อยดึงข้อมูลเต็มหลังตรวจสิทธิ์. เก็บเอกสารมินิมัลในดัชนี เช่น ID และป้ายที่ไม่ละเอียดอ่อนซึ่งปลอดภัยที่จะแสดงให้ใครก็ตามที่เข้าถึง UI ได้ เมื่อผู้ใช้คลิกผลลัพธ์ แอปของคุณโหลดระเบียนเต็มจากฐานข้อมูลหลักและใช้กฎสิทธิ์จริงที่นั่น

วิธีนี้ลดความเสี่ยงการรั่วไหล แต่ทำให้ผลลัพธ์ให้ข้อมูลน้อยและต้องระมัดระวังข้อความใน UI เพื่อไม่ให้ป้าย "ปลอดภัย" เปิดเผยข้อมูลลับโดยไม่ตั้งใจ

Approach B: เก็บแอตทริบิวต์สิทธิ์ในดัชนีแล้วกรองที่นั่น. รวมฟิลด์อย่าง tenant_id, team_id, owner_id, ธงบทบาท หรือ project_id ในเอกสารที่จัดทำดัชนี ทุกคำค้นเพิ่มตัวกรองที่ตรงกับขอบเขตของผู้ใช้ปัจจุบัน

วิธีนี้ให้ผลลัพธ์ที่เร็วและมีบริบทดี รวมทั้งออโต้คอมพลีทที่ดี แต่ทำได้เมื่อกฎการเข้าถึงสามารถแสดงเป็นตัวกรองเท่านั้น หากสิทธิ์ขึ้นกับตรรกะซับซ้อน (เช่น "มอบหมาย หรือ อยู่ในสแตนด์บายสัปดาห์นี้ หรือ เป็นส่วนหนึ่งของ incident") มันจะยากที่จะทำให้ถูกต้อง

Approach C: ไฮบริด. กรองหยาบในดัชนี แล้วตรวจสิทธิ์สุดท้ายในฐานข้อมูล. กรองในดัชนีด้วยแอตทริบิวต์ที่เสถียรและกว้าง (tenant, workspace, customer) แล้วรีเช็คสิทธิ์บนชุดไอดีผู้สมัครที่เล็กในฐานข้อมูลหลักก่อนส่งคืนอะไร

วิธีนี้มักปลอดภัยที่สุดสำหรับแอปจริง: ดัชนียังเร็ว และฐานข้อมูลยังเป็นแหล่งความจริง

การเลือกแบบ

เลือก A เมื่อคุณต้องการตั้งค่าที่ง่ายที่สุดและยอมรับผลลัพธ์ที่มีบริบทน้อยได้ เลือก B เมื่อคุณมีขอบเขตชัดเจนและค่อนข้างคงที่ (multi-tenant, team-based) และต้องการออโต้คอมพลีทที่เร็วมาก เลือก C เมื่อมีบทบาทมาก ข้อยกเว้น หรือกฎต่อระเบียนที่เปลี่ยนบ่อย สำหรับข้อมูลที่มีความเสี่ยงสูง (ทรัพยากรบุคคล การเงิน การแพทย์) ควรเลือก C เพราะ "เกือบถูก" ไม่พอสำหรับกรณีเหล่านี้

ขั้นตอนทีละขั้น: ออกแบบดัชนีที่เคารพกฎการเข้าถึง

รันแผนทดสอบมุ่งเน้นการรั่วไหล
เปิดแอปสเตจเพื่อทดสอบการรั่วไหลผ่านจำนวน ผลการจัดกลุ่ม และสถานะว่าง
ทดสอบ

เริ่มด้วยการเขียนกฎการเข้าถึงเหมือนกำลังอธิบายให้เพื่อนร่วมทีมคนใหม่ฟัง หลีกเลี่ยงคำว่า "แอดมินเห็นทุกอย่าง" เว้นแต่ว่าจริง ๆ เป็นเช่นนั้น ระบุเหตุผลแทน: "เจ้าหน้าที่ซัพพอร์ตเห็นตั๋วจากผู้เช่าของตน ผู้นำทีมเห็นตั๋วจากหน่วยงานของตนเท่านั้น โน้ตส่วนตัวเห็นได้เฉพาะเจ้าของและเจ้าหน้าที่ที่มอบหมาย" หากคุณอธิบายไม่ได้ว่าทำไมคนถึงเห็นระเบียน จะยากในการเข้ารหัสอย่างปลอดภัย

ต่อไป เลือกตัวระบุที่เสถียรและกำหนดเอกสารค้นหาขั้นพื้นฐาน ดัชนีไม่ควรเป็นสำเนาเต็มของแถวฐานข้อมูล เก็บเฉพาะสิ่งที่ต้องใช้ค้นหาและแสดงในรายชื่อผล เช่น ชื่อ เรื่อง สถานะ และอาจมีตัวอย่างสั้นที่ไม่ละเอียดอ่อน เก็บฟิลด์ที่ละเอียดอ่อนไว้หลังการดึงข้อมูลครั้งที่สองพร้อมการตรวจสิทธิ์

จากนั้นตัดสินใจว่าสัญญาณสิทธิ์ใดที่กรองได้เร็ว นี่คือแอตทริบิวต์ที่กำหนดการเข้าถึงและเก็บในเอกสารทุกชิ้น เช่น tenant_id, org_unit_id, และธงขอบเขตจำนวนน้อย เป้าหมายคือให้ทุกคำค้นสามารถใช้ตัวกรองก่อนคืนผลได้ รวมทั้งออโต้คอมพลีท

เวิร์กโฟลว์ที่ใช้งานได้จริงมีดังนี้:

  1. กำหนดกฎการมองเห็นสำหรับแต่ละ entity (ตั๋ว ลูกค้า ใบแจ้งหนี้) เป็นภาษาธรรมดา
  2. สร้างสคีม่าเอกสารค้นหาที่มี record_id และฟิลด์ค้นหา/แสดงที่ปลอดภัยเท่านั้น
  3. เพิ่มฟิลด์สิทธิ์ที่กรองได้ (tenant_id, org_unit_id, visibility_level) ในทุกเอกสาร
  4. จัดการข้อยกเว้นด้วยการมอบสิทธิ์แบบชัดเจน: เก็บ allowlist (ไอดีผู้ใช้) หรือไอดีกลุ่มสำหรับรายการที่แชร์

รายการที่แชร์และข้อยกเว้นคือจุดที่การออกแบบล้มเหลว หากตั๋วแชร์ข้ามทีม อย่าแค่เพิ่ม boolean ใช้การมอบสิทธิ์แบบชัดเจนที่ตรวจสอบได้ด้วยตัวกรอง หาก allowlist ใหญ่ ให้ใช้การมอบสิทธิ์แบบกลุ่มแทนผู้ใช้รายบุคคล

การรักษาความสอดคล้องของดัชนีโดยไม่เกิดความประหลาดใจ

เป็นเจ้าของการนำการค้นหามาใช้ของคุณ
ควบคุมได้ด้วยการส่งออกซอร์สโค้ดจริงสำหรับโฮสต์เองและการตรวจสอบ
ส่งออกโค้ด

ประสบการณ์การค้นหาที่ปลอดภัยขึ้นอยู่กับสิ่งน่าเบื่ออย่างหนึ่งที่ทำให้ดี: ดัชนีต้องสะท้อนความจริง หากระเบียนถูกสร้าง เปลี่ยน แก้ไข หรือลบ ผลการค้นหาต้องตามทันอย่างรวดเร็วและคาดเดาได้

ติดตามการสร้าง อัปเดต ลบ

ปฏิบัติกับการจัดทำดัชนีเป็นส่วนหนึ่งของวงจรชีวิตข้อมูล แบบจำลองที่มีประโยชน์คือ: ทุกครั้งที่แหล่งความจริงเปลี่ยน คุณส่งเหตุการณ์และตัวจัดทำดัชนีตอบสนอง

วิธีที่ใช้กันทั่วไปได้แก่ ทริกเกอร์ฐานข้อมูล เหตุการณ์จากแอป หรือคิวงาน สิ่งสำคัญคืออย่าให้เหตุการณ์หายไป หากแอปบันทึกระเบียนแต่ดัชนีล้มเหลว จะเกิดพฤติกรรมสับสนเช่น "ฉันรู้ว่ามันมี แต่การค้นหาไม่เจอ"

การเปลี่ยนแปลงสิทธิ์คือการเปลี่ยนแปลงดัชนี

การรั่วไหลหลายครั้งเกิดเมื่อเนื้อหาอัปเดตถูกต้อง แต่เมตาดาต้าสิทธิ์ไม่อัปเดต การเปลี่ยนสิทธิ์มาจากการอัปเดตบทบาท การย้ายทีม การโอนความเป็นเจ้าของ การย้ายลูกค้า หรือการรวมตั๋ว

ให้การเปลี่ยนแปลงสิทธิ์เป็นเหตุการณ์สำคัญ หากการค้นหาของคุณพึ่งพาตัวกรอง tenant หรือ team ให้แน่ใจว่าเอกสารที่จัดทำดัชนีรวมฟิลด์ที่ต้องใช้ในการบังคับนั้น (tenant_id, team_id, owner_id, allowed_role_ids) เมื่อตัวเหล่านี้เปลี่ยน ให้รีอินเด็กซ์

ส่วนยากคือขอบเขตผลกระทบ การเปลี่ยนบทบาทอาจกระทบหมื่น ๆ ระเบียน วางแผนเส้นทางรีอินเด็กซ์แบบกลุ่มที่มีการติดตามความคืบหน้า การลองใหม่ และวิธีหยุดชั่วคราว

วางแผนสำหรับ eventual consistency

แม้มีเหตุการณ์ดี ก็จะมีช่วงเวลาที่ดัชนียังตามไม่ทัน ตัดสินใจว่าผู้ใช้ควรเห็นอะไรในวินาทีแรกหลังการเปลี่ยน

สองกฎช่วยได้:

  • ทำให้ความล่าช้าเป็นเรื่องสม่ำเสมอ หากการจัดทำดัชนีปกติใช้ 2–5 วินาที ให้ตั้งความคาดหวังนั้นเมื่อจำเป็น
  • เลือกให้หายไปดีกว่ารั่วไหล ปลอดภัยกว่าที่ระเบียนที่เพิ่งได้รับสิทธิ์จะปรากฏช้ากว่าให้ระเบียนที่เพิ่งถูกถอนสิทธิ์ยังปรากฏอยู่

เพิ่มทางเลือกที่ปลอดภัยเมื่อดัชนีค้าง

การค้นหาเพื่อค้นพบ แต่การดูรายละเอียดคือที่ที่การรั่วไหลทำร้ายจริง ทำการตรวจสิทธิ์อีกครั้งเมื่ออ่านรายละเอียดก่อนแสดงฟิลด์ละเอียดอ่อน หากผลลัพธ์เล็ดรอดเพราะดัชนีค้าง หน้ารายละเอียดยังต้องบล็อกการเข้าถึง

รูปแบบที่ดีคือ: แสดงตัวอย่างขั้นต่ำในการค้นหา แล้วตรวจสิทธิ์อีกครั้งเมื่อผู้ใช้เปิดระเบียน (หรือขยายตัวอย่าง) หากการตรวจล้มเหลว ให้แสดงข้อความชัดเจนและลบรายการออกจากผลลัพธ์เมื่อรีเฟรชครั้งถัดไป

ความผิดพลาดทั่วไปที่ทำให้ข้อมูลรั่วไหล

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

ออโต้คอมพลีทเป็นแหล่งรั่วไหลบ่อย ๆ คำแนะนำมักขับเคลื่อนโดยการค้นหา prefix ที่เร็วซึ่งข้ามการตรวจสิทธิ์เต็มรูปแบบ UI ดูปลอดภัย แต่ตัวอักษรเดียวอาจเปิดเผยชื่อลูกค้าหรืออีเมล ออโต้คอมพลีทต้องรันตัวกรองการเข้าถึงเดียวกับการค้นหาเต็ม หรือสร้างจากชุดคำแนะนำที่กรองล่วงหน้า (เช่น แยกตามผู้เช่าและบทบาท)

ยอดรวมแฟคเซ็ตและป้าย "ประมาณ 1,243 ผลลัพธ์" เป็นการรั่วไหลเงียบ ยอดรวมยืนยันการมีอยู่แม้คุณจะซ่อนรายการ หากคำนวณยอดรวมตามกฎการเข้าถึงไม่ได้อย่างปลอดภัย ให้แสดงข้อมูลน้อยลงหรือไม่แสดงยอดรวม

แคชเป็นอีกสาเหตุทั่วไป แคชที่แชร์ระหว่างผู้ใช้ บทบาท หรือผู้เช่าอาจสร้าง "ผีผลลัพธ์" ที่ผู้ใช้หนึ่งเห็นผลลัพธ์ที่สร้างให้คนอื่น เกิดขึ้นได้กับ edge cache แคชระดับแอป และแคชในหน่วยความจำของบริการค้นหา

เช็คลิสต์ช่องโหว่ที่ควรตรวจเร็ว:

  • ออโต้คอมพลีทและการค้นหาล่าสุดถูกกรองด้วยกฎเดียวกับการค้นหาเต็ม
  • ยอดรวมแฟคเซ็ตและตัวเลขถูกคำนวณหลังการตรวจสิทธิ์
  • คีย์แคชรวม tenant ID และลายเซ็นสิทธิ์ (บทบาท ทีม ไอดีผู้ใช้)
  • โลกและการวิเคราะห์ไม่เก็บคำค้นหรือตัวอย่างที่ละเอียดอ่อนแบบดิบ

สุดท้าย ระวังตัวกรองกว้างเกินไป "กรองตาม tenant เท่านั้น" เป็นข้อผิดพลาดคลาสสิกของ multi-tenant แต่เกิดขึ้นภายในผู้เช่าเดียวได้เช่นกัน: กรองตาม "แผนก" เมื่อการเข้าถึงเป็นแบบแถวต่อแถว ตัวอย่าง: เจ้าหน้าที่ซัพพอร์ตค้นหา "refund" แล้วได้ผลลัพธ์ข้ามลูกค้าทั้งผู้เช่า รวมทั้งบัญชี VIP ที่ควรเห็นได้แค่ทีมเล็กกว่า การแก้โดยหลักการคือ: บังคับใช้กฎระดับแถวในทุกเส้นทางคำค้น (search, autocomplete, facets, exports) ไม่ใช่แค่หน้าเปิดระเบียน

รายละเอียดความเป็นส่วนตัวและความปลอดภัยที่คนมักลืม

ออกแบบเพื่อความปลอดภัยแบบหลายผู้เช่า
สร้างแอปหลายผู้เช่าที่ทุกคำค้นทำงานเหมือนการมองข้อมูลเฉพาะของผู้ใช้
เริ่มเลย

การออกแบบหลายแบบเน้นว่า "ใครเห็นอะไร" แต่การรั่วไหลเกิดจากขอบเขต: สถานะว่าง เวลา และเบาะแสเล็ก ๆ การค้นหาที่คำนึงถึงสิทธิ์ต้องปลอดภัยแม้จะคืนค่าเป็นศูนย์

การยืนยันด้วยการไม่มีผลลัพธ์เป็นช่องโหว่ง่าย หากผู้ใช้ไม่มีสิทธิ์ค้นหาชื่อลูกค้าหรืออีเมลแล้วได้ข้อความเฉพาะเช่น "No access" หรือ "You don't have permission" คุณได้ยืนยันการมีอยู่ของระเบียนแล้ว ปฏิบัติต่อ "ไม่มีผลลัพธ์" เป็นผลลัพธ์ดีฟอลต์สำหรับทั้ง "ไม่มีอยู่" และ "มีอยู่แต่ไม่อนุญาต" รักษาเวลาในการตอบและถ้อยคำให้สม่ำเสมอเพื่อไม่ให้คนเดาจากความเร็ว

การจับคู่บางส่วนที่ละเอียดอ่อน

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

ชุดกฎปฏิบัติได้:

  • ต้องเป็นการจับคู่ตรงสำหรับฟิลด์ความเสี่ยงสูง (อีเมล เบอร์โทร รหัส)
  • หลีกเลี่ยงการแสดงสแนปชอตที่เน้นข้อความที่ซ่อนอยู่
  • พิจารณาปิดออโต้คอมพลีทสำหรับฟิลด์ละเอียดอ่อนทั้งหมด

ถ้าการโชว์แม้แต่ตัวอักษรเดียวช่วยให้ใครบางคนเดาข้อมูล ให้ถือว่าฟิลด์นั้นละเอียดอ่อน

การควบคุมการใช้งานที่ไม่สร้างความเสี่ยงใหม่

เอ็นด์พอยต์การค้นหาเป็นเป้าสำหรับการโจมตีแบบสำรวจ: ลองคำค้นจำนวนมากเพื่อแมปสิ่งที่มี เพิ่มอัตราจำกัดและการตรวจจับพฤติกรรมผิดปกติ แต่ระวังสิ่งที่เก็บเก็บบันทึก โลกที่รวมคำค้นดิบอาจเป็นแหล่งรั่วไหลที่สอง

ทำให้เรียบง่าย: จำกัดอัตราต่อผู้ใช้ ต่อไอพี และต่อผู้เช่า; เก็บบันทึกเป็นจำนวน เวลา และรูปแบบหยาบ (ไม่ใช่ข้อความคำค้นเต็ม); แจ้งเตือนเมื่อมีคำค้นที่เกือบพลาดซ้ำ ๆ (เช่น ไอดีเรียงกัน); และบล็อกหรือยกระดับการยืนยันหลังความล้มเหลวซ้ำ

ทำให้ข้อผิดพลาดน่าเบื่อ ใช้ข้อความและสถานะว่างเดียวกันสำหรับ "ไม่มีผลลัพธ์" "ไม่อนุญาต" และ "ตัวกรองไม่ถูกต้อง" ยิ่ง UI พูดน้อย ยิ่งเปิดเผยน้อย

ตัวอย่าง: ทีมซัพพอร์ตค้นหาตั๋วข้ามลูกค้า

จากการสร้างสู่การปรับใช้
ปรับใช้บริการการค้นหาที่ปลอดภัยของคุณไปยัง AppMaster Cloud หรือคลาวด์ของคุณเมื่อพร้อม
ปรับใช้แอป

เจ้าหน้าที่ซัพพอร์ตชื่อ Maya ทำงานในทีมที่ดูแลบัญชีลูกค้า 3 ราย เธอมีช่องค้นหาเดียวในส่วนหัวแอป ผลิตภัณฑ์มีดัชนีรวมสำหรับตั๋ว รายชื่อติดต่อ และบริษัท แต่ทุกผลลัพธ์ต้องปฏิบัติตามกฎการเข้าถึง

Maya พิมพ์ "Alic" เพราะคนโทรบอกชื่อ Alice ออโต้คอมพลีทแสดงคำแนะนำไม่กี่รายการ เธอคลิก "Alice Nguyen - Ticket: Password reset" ก่อนเปิดแอปตรวจสอบสิทธิ์สำหรับระเบียนนั้นอีกครั้ง หากตั๋วยังมอบหมายให้ทีมของเธอและบทบาทของเธออนุญาต เธอจะเข้าไปยังตั๋วนั้นได้

สิ่งที่ Maya เห็นในแต่ละขั้นตอน:

  • กล่องค้นหา: คำแนะนำปรากฏเร็ว แต่มีเฉพาะรายการที่เธอเข้าถึงได้ตอนนี้
  • รายการผลลัพธ์: หัวเรื่องตั๋ว ชื่อลูกค้า เวลาอัปเดตล่าสุด ไม่มีตัวแทนข้อความว่า "คุณไม่มีสิทธิ์"
  • รายละเอียดตั๋ว: มุมมองเต็มโหลดหลังการตรวจสิทธิ์ฝั่งเซิร์ฟเวอร์อีกครั้ง หากการตรวจล้มเหลว แอปจะแสดงว่า "Ticket not found" (ไม่ใช่ "forbidden")

เปรียบเทียบกับ Leo เจ้าหน้าที่ใหม่ที่ฝึกงาน บทบาทของเขาเห็นเฉพาะตั๋วที่ระบุว่า "Public to Support" และสำหรับลูกค้าหนึ่งรายเท่านั้น Leo พิมพ์ "Alic" เขาเห็นคำแนะนำจำนวนน้อยกว่า และไม่มีรายการที่หายไปเป็นเบาะแส ไม่แสดงยอดรวมว่า "มี 5 ผลลัพธ์" ที่บอกว่ามีการจับคู่อื่นอยู่ UI แสดงเฉพาะสิ่งที่เขาเปิดได้

ต่อมา ผู้จัดการย้าย "Alice Nguyen - Password reset" จากทีมของ Maya ไปยังทีมขึ้นศูนย์เฉพาะ ในช่วงเวลาอันสั้น (มักเป็นวินาทีถึงไม่กี่นาที ขึ้นกับแนวทางซิงค์ของคุณ) การค้นหาของ Maya จะหยุดคืนค่านั้น หากเธอมีหน้ารายละเอียดเปิดและรีเฟรช แอปจะตรวจสิทธิ์อีกครั้งและตั๋วจะหายไป

นั่นคือพฤติกรรมที่ต้องการ: พิมพ์เร็ว ผลลัพธ์เร็ว โดยไม่มีเบาะแสการรั่วไหลผ่านยอดรวม ตัวอย่าง หรือรายการค้างในดัชนี

เช็คลิสต์และขั้นตอนถัดไปสำหรับการนำไปใช้อย่างปลอดภัย

การค้นหาแบบรวมที่คำนึงถึงสิทธิ์จะ "เสร็จ" เมื่อขอบเขตน่าเบื่อปลอดภัยแล้ว รั่วไหลหลายกรณีเกิดในจุดที่ดูเหมือนไม่เป็นอันตราย: ออโต้คอมพลีท ยอดรวม และการส่งออก

การตรวจสอบความปลอดภัยด่วน

ก่อนปล่อย ให้เดินผ่านการตรวจเหล่านี้ด้วยข้อมูลจริง ไม่ใช่ตัวอย่าง:

  • ออโต้คอมพลีท: ห้ามแนะนำชื่อเรื่อง ชื่อ หรือไอดีที่ผู้ใช้เปิดไม่ได้
  • ยอดรวมและแฟคเซ็ต: หากแสดงยอดรวม ให้คำนวณหลังการตรวจสิทธิ์ (หรือไม่แสดงยอดรวม)
  • การส่งออกและการกระทำเป็นกลุ่ม: การส่งออก "การค้นหาปัจจุบัน" ต้องตรวจสิทธิ์ต่อแถวเมื่อส่งออก
  • การเรียงลำดับและการเน้น: อย่าเรียงหรือเน้นโดยใช้ฟิลด์ที่ผู้ใช้ไม่มีสิทธิ์เห็น
  • "ไม่พบ" vs "ห้าม": สำหรับเอนทิตีละเอียดอ่อน ให้พิจารณารูปแบบการตอบเหมือนกันเพื่อผู้ใช้จะไม่ยืนยันการมีอยู่

แผนทดสอบที่ทำได้

สร้างเมทริกซ์บทบาทเล็ก ๆ (บทบาท x เอนทิตี) และชุดข้อมูลที่ตั้งใจให้เป็นกรณียาก: ระเบียนที่แชร์ ระเบียนที่เพิ่งถูกยกเลิกการเข้าถึง และคู่ที่เหมือนกันข้ามผู้เช่า

ทดสอบสามรอบ: (1) ทดสอบเมทริกซ์บทบาท ยืนยันว่าระเบียนที่ถูกปฏิเสธไม่ปรากฏในผลลัพธ์ คำแนะนำ ยอดรวม หรือการส่งออก; (2) "ลองทำลาย" ทดสอบ วางไอดี วางอีเมลหรือเบอร์โทร และลองการจับคู่บางส่วนที่ต้องไม่คืนค่าอะไร; (3) ทดสอบเวลาและแคช เปลี่ยนสิทธิ์และยืนยันว่าผลลัพธ์อัปเดตเร็วโดยไม่มีคำแนะนำหรือรายการค้าง

ในเชิงปฏิบัติ ให้วางแผนสำหรับวันที่ผลการค้นหา "ดูผิด" บันทึกบริบทคำค้น (ผู้ใช้ บทบาท ผู้เช่า) และตัวกรองสิทธิ์ที่ใช้ แต่หลีกเลี่ยงการเก็บสตริงคำค้นหรือตัวอย่างละเอียดอ่อนแบบดิบ สำหรับการดีบักที่ปลอดภัย สร้างเครื่องมือสำหรับผู้ดูแลระบบที่อธิบายได้ว่าทำไมระเบียนถึงตรงและทำไมถึงได้รับอนุญาต

ถ้าคุณกำลังสร้างบน AppMaster (appmaster.io) แนวทางปฏิบัติที่เป็นประโยชน์คือเก็บการค้นหาเป็นโฟลว์ฝั่งเซิร์ฟเวอร์: โมเดลเอนทิตีและความสัมพันธ์ใน Data Designer บังคับกฎการเข้าถึงใน Business Processes เดียวกัน และนำการตรวจสิทธิ์นั้นกลับมาใช้กับออโต้คอมพลีท รายการผล และการส่งออก เพื่อให้มีที่เดียวที่ต้องถูกต้อง

ง่ายต่อการเริ่มต้น
สร้างบางสิ่งที่ น่าทึ่ง

ทดลองกับ AppMaster ด้วยแผนฟรี
เมื่อคุณพร้อม คุณสามารถเลือกการสมัครที่เหมาะสมได้

เริ่ม