ไวต์เปเปอร์ด้านความปลอดภัยของ MeshLaw
2026-05-21 v0.1 · สำหรับทีมกฎหมายและทีม IT ตรวจสอบ
เอกสารฉบับนี้สรุปนโยบายการประมวลผลข้อมูล การแยกข้อมูล การเข้ารหัส และการควบคุมการเข้าถึงของ MeshLaw โดยอ้างอิงจากข้อเท็จจริงของการนำไปใช้งานจริง (โค้ด การ migrate และการตั้งค่าการใช้งานจริง) และเมื่อมีการตรวจสอบหรือทำ due diligence เราจะแสดงบรรทัดที่เกี่ยวข้องประกอบด้วย
1. โครงสร้างของระบบ
| ส่วนประกอบ | เทคโนโลยี | หมายเหตุ |
|---|---|---|
| เกตเวย์ | Moleculer (Node/Bun) :4098 | ทางเข้า HTTP ตรวจสอบ JWT + ฉีดบริบท RLS |
| ฐานข้อมูล | PostgreSQL 16 + pgvector | อินสแตนซ์เดียว แยกข้อมูลด้วย RLS ตาม team_id |
| แบ็กเอนด์ AI | vLLM (โฮสต์ภายในองค์กร) | ไม่ส่งออก API ภายนอก — ข้อมูลคดีจะไม่ออกไปยังผู้ให้บริการ LLM ภายนอก |
| อีเมล | Resend (ยืนยันโดเมนแล้ว) | ใช้เฉพาะการสมัครและรหัสผ่าน ไม่ส่งเนื้อหาของคดี |
| การแจ้งเตือนมือถือ | APNs + FCM | เฉพาะ title/body + data เท่านั้น ไม่มีเนื้อหาของคดี |
โฮสติ้ง: Vultr รีเจียนโซล (Seoul) — ข้อมูลตั้งอยู่ในประเทศเกาหลี การเข้าถึง SSH สำหรับการใช้งานจริง: ใช้การยืนยันด้วยคีย์เท่านั้น (ปิดการใช้รหัสผ่าน)
2. การแยกข้อมูลแบบ Multi-tenant
2.1 Row-Level Security ของ PostgreSQL
ทุกตารางในโดเมนเปิดใช้งาน FORCE ROW LEVEL SECURITY:
- แยกข้อมูลโดยตรง (คอลัมน์ team_id): matters, clients, advisories, audit_log, notifications, llm_usage, team_token_quota, messages, device_tokens, stripe_webhook_events, invoice_receipts
- แยกข้อมูลผ่าน JOIN (matter_id → matters.team_id): matter_events, invoices, timesheet_entries, writs, approvals, matter_refs, vault_files, matter_acl, deadlines
นโยบาย: team_id = app_current_team_id() (USING + WITH CHECK) โดย app_current_team_id() จะอ่านค่า GUC ของทรานแซกชัน app.team_id
2.2 การแยกบทบาทแบบ NOSUPERUSER
เกตเวย์สำหรับการใช้งานจริงเชื่อมต่อฐานข้อมูลด้วย ROLE meshlaw_app (NOSUPERUSER · NOBYPASSRLS) ส่วนเครื่องมือ dev / migration แยกเป็น superuser ต่างหาก — ทราฟฟิกการใช้งานประจำวันจึงไม่มีผู้ใช้ที่มี BYPASSRLS เข้ามาเกี่ยวข้อง เริ่มใช้เมื่อ 2026-05-05
2.3 การฉีดค่า GUC ของทรานแซกชัน
sql.begin(async (tx) =>
await tx`select set_config('app.team_id', ${teamId}, true)`
await tx`select set_config('app.user_id', ${userId}, true)`
return fn(tx)
เนื่องจากเป็น SET LOCAL จึงถูกล้างโดยอัตโนมัติเมื่อทรานแซกชันสิ้นสุด มีการ wrap ครบ 50/50 ของแอ็กชันในโดเมน ส่วนที่เหลืออีก 7 รายการเป็น raw โดยตั้งใจ เช่น การ lookup password_hash ใน auth.signup/login — ไม่มีช่องทางรั่วไหลของข้อมูล
2.4 การ map JWT → ctx.meta.user
onBeforeCall ของเกตเวย์จะตรวจสอบ JWT → ฉีด ctx.meta.user = { id, team, role } ทุกเส้นทางในโดเมนรวมอยู่ใน AUTH_REQUIRED_PREFIXES ดังนั้นหากไม่มีโทเคนจะได้ 401
2.5 การป้องกัน Regression
การแยกข้อมูล tenant จะถูกทดสอบ regression ก่อนทุกการ deploy ในชุด e2e §7 (RLS):
- การเรียกที่ไม่ได้ยืนยันตัวตน → 401
- JWT ไม่ถูกต้อง → 401
- JWT ที่ถูกต้องเข้าถึงได้เฉพาะข้อมูลของ team ตัวเองเท่านั้น → 200
3. การคุ้มครองข้อมูลส่วนบุคคล (PII)
3.1 เลขประจำตัวประชาชน
การจัดเก็บ: เข้ารหัสด้วย pgp_sym_encrypt (BYTEA rrn_encrypted) + เก็บ 4 หลักสุดท้าย (rrn_last4) การแสดงผล: UI ฝั่งไคลเอนต์บังคับปิดบังด้วย maskRRN() → XXXXXX-XXX{last4} หากรูปแบบไม่ตรงจะคืนค่าเป็นสตริงว่าง (ป้องกันการแสดงค่า raw) มี unit test regression 8 รายการ
3.2 รหัสผ่าน
จัดเก็บเป็น bcrypt hash ฝั่งไคลเอนต์แสดงผลแบบเรียลไทม์ตามกฎ 4 ข้อขณะป้อน (8 ตัวอักษร / ตัวอักษร / ตัวเลข / อักขระพิเศษ) ใช้ HTTPS เท่านั้น — บิลด์ iOS Release ไม่ได้ตั้งค่า NSAllowsArbitraryLoads
3.3 การจัดการโทเคน
- JWT: TTL สั้น (ค่าเริ่มต้น 30 นาที), HS256
- Refresh: หมุนเวียนโทเคน (rotation) + ตรวจจับการนำกลับมาใช้ซ้ำ (reuse detection) ค่า plaintext ส่งให้ผู้ใช้เพียงครั้งเดียว ส่วนในฐานข้อมูลเก็บเฉพาะ bcrypt hash เมื่อตรวจพบการใช้ซ้ำจะ revoke ทั้ง chain
3.4 ACL ระดับคดี
นอกเหนือจากขอบเขต team ของ RLS ยังมีการแยกข้อมูลเพิ่มเติมในระดับคดี (matter_acl) มี 4 บทบาท (owner ⊃ editor ⊃ viewer) ระบบแมสเซนเจอร์ v0.1.6 นำมาใช้ — การดูรายการช่องของคดีต้องเป็น viewer ขึ้นไป การเขียนต้องเป็น editor ขึ้นไป
4. บันทึกการตรวจสอบ (Audit Log)
แอ็กชันที่บันทึกอัตโนมัติลงตาราง audit_log:
- การ CRUD คดี และการ grant/revoke ACL
- การอนุมัติ / ปฏิเสธ / ขอแก้ไขในกระบวนการอนุมัติ (status_before/after, comment)
- การออกใบแจ้งหนี้ และใบเสร็จการรับชำระ (delta_won, total)
- การ rollup การใช้งาน → invoice/timesheet
- การ CRUD เอกสารอ้างอิง
แต่ละ row ประกอบด้วย: actor_name, target_kind, target_id, http_status, matter_id, meta(JSONB), created_at มีการบังคับใช้ RLS — ไม่สามารถดู audit ของ tenant อื่นได้
5. การควบคุมสิทธิ์
5.1 การอนุมัติ (matter approvals)
มี actor guard ฝั่งเซิร์ฟเวอร์ — computeApprovalChainAdvance(steps, status, currentUserId) เฉพาะผู้ใช้ที่ตรงกับ approver_id ของขั้นตอนที่กำลังดำเนินอยู่เท่านั้นจึงจะทำแอ็กชันได้ หากไม่ตรงจะได้ 403 NOT_APPROVER ใช้ guard เดียวกันทั้งเดสก์ท็อปและมือถือ มี unit test 7 รายการ
5.2 RBAC (บทบาทของระบบ)
users.role_id → ตาราง roles (admin/partner/associate/staff) auth.invite เป็นผู้กำหนดบทบาท (เฉพาะ admin เท่านั้นที่ออกได้)
6. การประมวลผลข้อมูล
6.1 การเรียกใช้โมเดล AI
ใช้ vLLM ภายในองค์กร (เครือข่ายภายใน Tailscale) — ไม่ส่งออก API ภายนอก เนื้อหาคำขอ LLM (บริบทของคดี เอกสาร) จะไม่ออกไปภายนอกองค์กร มีการบันทึกโทเคนและค่าใช้จ่ายของการเรียกใช้ลงตาราง llm_usage (ตามขอบเขต team ของ RLS)
6.2 ไฟล์ (Vault)
- การจัดเก็บ: ดิสก์เซิร์ฟเวอร์ (
storage_directoryแยกตามแต่ละคดี) - เมตาดาตา: ตาราง
vault_files(file_name, mime, size_bytes, text_content) - การจัดทำดัชนี: สกัดข้อความแล้วจัดเก็บใน
text_content→ ค้นหาแบบรวม ⌘K (บังคับใช้ RLS) - PDF แบบ multimodal: แปลงหน้าเป็น JPEG ด้วย mupdf → ส่งให้ vision encoder ของ vLLM (ไม่ออกภายนอก)
6.3 อีเมล
โดเมน Resend meshlaw.ai (ยืนยัน DKIM/SPF/DMARC แล้ว) เนื้อหา: เฉพาะการสมัคร การเชิญ (invite) และการรีเซ็ตรหัสผ่านเท่านั้น — ไม่มีเนื้อหาของคดี
7. ความปลอดภัยของโครงสร้างพื้นฐาน
7.1 การรับส่งข้อมูล
เกตเวย์: ใช้ HTTPS เท่านั้น (Caddy) ทั้ง iOS Release และ Android Release ใช้เฉพาะ prod URL (เฉพาะ Debug เท่านั้นที่ใช้ localhost)
7.2 การแจ้งเตือนมือถือ
- APNs JWT (.p8) — Apple Developer Team ID + Key ID
- FCM HTTP v1 — Firebase service account JSON
- เนื้อหาของการแจ้งเตือนเป็นเพียงเมตาดาตา (title/body + data.type สำหรับ hint การ route) — ไม่มีเนื้อหาของคดี
- โทเคนของอุปกรณ์: ตาราง
device_tokens(ตามขอบเขต team ของ RLS)
7.3 การเข้าถึงสำหรับการใช้งานจริง
- การเข้าถึง SSH: ยืนยันตัวตนด้วยคีย์ (แนะนำสำหรับการใช้งานจริง)
- ฐานข้อมูล: docker-compose ผูกไว้ที่
127.0.0.1:54322แบบ localhost bind only — ไม่เปิดสู่อินเทอร์เน็ตภายนอก เฉพาะคอนเทนเนอร์เกตเวย์ภายในโฮสต์เท่านั้นที่เข้าถึงได้ (network_mode: host) - การสำรองข้อมูล:
/var/backups/meshlaw-db-*.sql.gz(ปัจจุบันทำเอง วางแผนทำอัตโนมัติ) - เมื่อจะ apply migration ต้องสำรองข้อมูลล่วงหน้าเสมอ (ระเบียบการใช้งานจริง)
7.4 การชำระเงิน Stripe
ตรวจสอบลายเซ็น Webhook + guard ความเป็น idempotent (stripe_webhook_events) ข้อมูลบัตรอยู่ใน Stripe Vault — ไม่จัดเก็บเอง (ลดขอบเขต PCI ให้น้อยที่สุด)
8. แนวทางด้านการปฏิบัติตามข้อกำหนด (Compliance)
| รายการ | สถานะ |
|---|---|
| กฎหมายคุ้มครองข้อมูลส่วนบุคคล (PIPA) | ประมวลผลตามปกติ · จัดทำ DPA แยกต่างหาก |
| ISMS-P | อยู่ระหว่างพิจารณา (จะแจ้งแยกต่างหากเมื่อยื่นขอรับรอง) |
| เครื่องหมาย KISA | อยู่ระหว่างพิจารณา |
| GDPR | ไม่อยู่ในขอบเขต (จำกัดเฉพาะในประเทศ) |
| ZDR (Zero Data Retention) | เป็นตัวเลือกเชิงนโยบาย — เป็นข้อตกลงแนบเมื่อทำสัญญาแผน Pro+ ปัจจุบันใช้เฉพาะ vLLM ภายในองค์กรจึงไม่มีการเปิดเผยข้อมูลสู่การฝึกโมเดลภายนอกตั้งแต่ต้น |
⚠️ ISMS-P / เครื่องหมาย KISA อยู่ในขั้นตอนพิจารณา การใช้เครื่องหมายรับรองจะทำได้หลังจากได้รับการรับรองแล้วเท่านั้น
9. การตอบสนองต่อเหตุการณ์
9.1 โทเคนรั่วไหล
เมื่อตรวจพบการใช้ refresh ซ้ำ ระบบจะ revoke ทั้ง chain ของผู้ใช้โดยอัตโนมัติ การเรียก /auth/logout หรือเปลี่ยนรหัสผ่าน → revoke refresh ทั้งหมด
9.2 ข้อมูลรั่วไหล
เมื่อตรวจพบจะ rollback docker-compose ทันที + กู้คืนจากการสำรองฐานข้อมูล
9.3 การแจ้งผู้ใช้
เป้าหมายเชิงนโยบาย: แจ้งขอบเขตผลกระทบ ขั้นตอนการกู้คืน และการดำเนินการที่ผู้ใช้ต้องทำ ภายใน 72 ชั่วโมง (ระดับคำแนะนำตามกฎหมายคุ้มครองข้อมูลส่วนบุคคล §34) ปัจจุบันยังไม่มีระบบอัตโนมัติ — เมื่อเกิดเหตุผู้ดูแลระบบจะคำนวณขอบเขตผลกระทบและส่งอีเมลแจ้งแบบกลุ่มด้วยตนเอง
10. การโอนย้ายและลบข้อมูล
- การ Export: ผู้ใช้สามารถ export ข้อมูลของ team ตัวเองเป็น JSON (วางแผนใน v0.2)
- การลบ: ลบโดยตรงผ่าน UI ส่วนการลบบัญชีให้ส่งคำขอทางอีเมล → grace 30 วัน → cascade
- การเก็บรักษา: ค่าเริ่มต้นเก็บไว้ไม่จำกัด การเก็บรักษาตามกฎหมาย (เช่น กฎหมายภาษีเงินได้ 5 ปี) เป็นความรับผิดชอบของผู้ใช้
11. การขอตรวจสอบ
หากต้องการความร่วมมือในการตรวจสอบข้อเท็จจริงหรือทำ due diligence ของไวต์เปเปอร์ฉบับนี้ กรุณาส่งคำขอผ่าน หน้าติดต่อ หรืออีเมลฝ่ายขาย — เราจะจัดเตรียมเส้นทางโค้ด (หมายเลขบรรทัด) · สำเนา SQL ของ migration · ผลการทดสอบเจาะระบบ (เมื่อดำเนินการแล้ว) ให้
กล่องอีเมลของฝ่ายความปลอดภัยโดยเฉพาะ (เช่น compliance@meshlaw.ai) จะประกาศแยกต่างหากเมื่อยืนยันโดเมนและเตรียมการใช้งานจริงเสร็จสิ้น
กด ⌘P (Mac) / Ctrl+P (Win) แล้วเลือก "บันทึกเป็น PDF" หรือ ดาวน์โหลดต้นฉบับ Markdown