สมอง SML

คลังความรู้ / มาตรฐาน & กฎ

#standards#security#lessons#auth#multi-tenant#bugs

บทเรียนบั๊กสิทธิ์และการข้ามฐานข้อมูล

รวมบั๊กที่ตรวจพบและแก้แล้วในรอบ 2026-10-24 (branch dev) ด้านการยืนยันตัวตน การแบ่งสิทธิ์ และการแยกฐานข้อมูล พร้อมกฎที่ต้องจำ เช็กลิสต์ใช้งานจริงอยู่ที่ เช็กลิสต์ความปลอดภัย API: ตัวตน สิทธิ์ และช่องโหว่เว็บ (Secure API Checklist)

บั๊ก → วิธีแก้ → กฎที่ต้องจำ

รหัส อาการ วิธีแก้ กฎ
S1 POST /api/auth/google ที่ส่งแค่ email ก็ได้ session ของเจ้าของฐานข้อมูล (ไม่มี idToken) บังคับ idToken, ตรวจ aud และ email_verified ตัวตนต้องมาจากข้อมูลที่ตรวจแล้ว ห้ามเชื่อ body
S2 GET/PUT screen-rights, GET members ตรวจแค่มี session แต่เรียก backend ด้วยกุญแจ Admin → Member ให้สิทธิ์จอตัวเองเต็มได้ isWorkspaceAdmin() ตรวจว่าเป็น Admin ของฐานนั้นจริง (Demo ถูกปฏิเสธ) route ที่ใช้กุญแจ Admin ต้องตรวจ Admin ฝั่ง server
B1 /blob/insert ข้ามนโยบาย write lockdown → ผู้ใช้ระดับ 1 เขียนตาราง sml_user_list / gl_journal_detail ได้ ใช้ ValidateClientInsert() ตัวเดียวกับ /query/exec ทุกทางเขียนจากเบราว์เซอร์ใช้นโยบายเดียวกัน
B2 route แผนที่ไม่ต้อง login แต่ ?db= เลือกฐานข้อมูลบริษัทได้ ผู้ไม่ login ถูกตรึงที่ smldemo ห้ามให้ผู้เรียกเลือก tenant เองเมื่อไม่ยืนยันตัวตน

รอบที่ 2: เสริมเกราะ Auth/API

  • getAdminApiKey() ไม่ส่งกุญแจ dev ใน production (ตอบ 503 NO_ADMIN_API_KEY)
  • Google OAuth redirect มี state (cookie + timingSafeEqual) กัน login CSRF
  • /api/auth/databases ตรวจว่าฐานข้อมูลอยู่ใน availableCompanies ของผู้ใช้
  • /api/admin/* ใช้ requireSystemAdmin() (ต้อง session.mode === "admin"); /api/fraudwarning|workmonitor ต้องมี session; /api/monitormap/tile POST ต้อง login และ single-flight
  • POST /api/workspace/databases ใช้ session.email เท่านั้น (ไม่รับอีเมลจาก client)

รอบที่ 3 และการตัดสินใจของลุงจืด (2026-10-24)

  • สิทธิ์จอแยกต่อฐานข้อมูล: เพิ่มคอลัมน์ database_name ใน sml_permissions_user / sml_permissions_group; Backend บังคับสิทธิ์ Add/Edit/Delete บน /process/* (doc/save, stocktools/pointdocsave, stocktools/stockbeginningsave), /query/exec, /query/execBatch, /blob/insert; ฝั่งหน้าจอผูก useScreenRights() ทุกจอ (เดิม TabsContext.screenRights บังคับแค่ฝั่งหน้าจอ backend ต้องตรวจซ้ำเสมอ) — ไฟล์ที่เกี่ยวข้อง admin/menu_permissions.go, admin/workspace_google.go
  • โหมดสาธิตดูระบบส่วนกลางได้แต่ห้ามเพิ่ม/แก้ไข/ลบ: isDemoCentralViewer() (ปุ่ม Demo, โดเมนสาธิต, บัญชีสาธารณะของ smldemo); GET ใช้ requireSystemAdminView() + ล็อก provider smldemo + ตัดฟิลด์ลับ (demoSafe); เขียนทุกชนิดได้ 403 DEMO_READ_ONLY; โซน /admin มีแถบ "ดูอย่างเดียว"
  • Login ผู้ดูแลส่วนกลาง (mode: "admin") แยกจากปุ่ม Google และปฏิเสธบัญชีสาธิต (DEMO_ADMIN_FORBIDDEN); เปลี่ยนรหัสผ่านตัวเอง ผ่าน /api/auth/change-password ตรวจรหัสเดิมก่อน (บัญชี Google ให้ไปเปลี่ยนที่ Google)

ที่มา

  • docs/kms/KMS_SECURITY_DATA_INTEGRITY_LESSONS.md ตาราง S1–S2, B1–B2, รอบที่ 2–3, "การตัดสินใจของลุงจืด" ข้อ 1, 3
  • ตรวจแล้วมีจริง: frontend/src/app/api/workspace/[...path], frontend/src/app/api/auth/change-password/route.ts, backend/.../admin/menu_permissions.go, blob/handler.go

ดูเพิ่ม

สารบัญมาตรฐานและกฎเหล็กของ SML Ai Account (Standards Overview) · เช็กลิสต์ความปลอดภัย API: ตัวตน สิทธิ์ และช่องโหว่เว็บ (Secure API Checklist) · Google Login, Multi-Tenant PDPA และหน้าเลือกโมดูลหลัง Login (Google OAuth, Tenant Isolation, Home Hub) · ความถูกต้องของข้อมูล: เงิน ภาษี Transaction เดียว และ Rebuild (Data Integrity, big.Rat, ExecBatch) · ภาพรวม Backend Go ของ SML Ai Account (Backend overview)