รายการตรวจสอบด้านประสิทธิภาพและความมั่นคงปลอดภัย (Test Checklist)
อ้างอิง TOR: ข้อ 4.7.2 (Checklist ประสิทธิภาพ/ความปลอดภัย), ภาคผนวก ก ข้อ 1.1.1 (มาตรฐานเว็บไซต์ภาครัฐ เวอร์ชัน 3.0) และข้อ 1.1.2 (มาตรฐานความมั่นคงปลอดภัยเว็บไซต์ พ.ศ. 2568) ฉบับ: 1.0 — วันที่ 3 ตุลาคม พ.ศ. 2569
ลักษณะของเอกสาร: เป็น การประเมินตนเอง (self-assessment) ของผู้รับจ้างจากการตรวจซอร์สโค้ดและการตั้งค่าของระบบสาธิต ไม่ใช่การรับรองจากหน่วยงานภายนอก สถานะใช้สัญลักษณ์ดังนี้ ผ่าน = มีหลักฐานในโค้ด/ผลทดสอบอัตโนมัติ · บางส่วน = ทำแล้วบางส่วนหรือทำได้เฉพาะในระบบสาธิต · ยังไม่ทำ = ยังไม่ได้ดำเนินการ (ระบุเหตุผล) · ต้องทำบน Production = ขึ้นกับโครงสร้างพื้นฐานจริง ผลตัวเลขจากการรันเครื่องมือให้ดูรายงานที่สร้างอัตโนมัติ (หัวข้อ 6) — เอกสารนี้ไม่ได้อ้างตัวเลขผลลัพธ์เอง การทดสอบเจาะระบบ (Penetration Test) ไม่ได้ดำเนินการในรอบนี้ตามคำสั่งของผู้ว่าจ้าง
1. Checklist ด้านประสิทธิภาพ (Performance)
| # | รายการตรวจ | เกณฑ์ | วิธีตรวจ/หลักฐาน | สถานะ |
|---|---|---|---|---|
| P-01 | First Contentful Paint หน้าแรกและหน้าแชต | ≤5 วินาที (TOR 12.2) | E2E tests/e2e/public.spec.ts / chat.spec.ts (FCP < 5s) + npm run report:perf | ผ่าน (ระดับเครื่องเดียว) |
| P-02 | Time To First Token ของคำตอบ | ≤15 วินาทีที่ p95 (TOR 12.2) | วัดทุกคำขอ (ApiRequestLog.ttftMs, Message.ttftMs) → /admin/sla-report, /documents/performance-report | ดูผลในรายงาน |
| P-03 | Error rate | ≤5% ที่ p95 (TOR 12.2) | ApiRequestLog.statusCode → SLA report; แจ้งเตือน error_rate เมื่อ >5% ใน 15 นาที | ผ่าน (มีการวัด+แจ้งเตือน) |
| P-04 | ผู้ใช้พร้อมกัน | ≥500 concurrent (ก.1.4.1, 4.7.6) | scripts/perf/load-test.ts ระดับเครื่องเดียว; ระดับ 500 ต้องใช้ HPA บน Kubernetes | บางส่วน / ต้องทำบน Production |
| P-05 | รองรับบัญชีผู้ใช้ 1,000,000 บัญชี | ก.1.4.2 | npm run seed:perf-users -- --count=1000000 → prisma/perf.db วัดเวลาค้นหาด้วย emailHash (unique index) | บางส่วน (วัดบน SQLite) |
| P-06 | SSE streaming ไม่ถูก buffer | ส่ง references ก่อนคำตอบ และ delta ทีละส่วน | header cache-control: no-cache, no-transform, x-accel-buffering: no; Ingress proxy-buffering: off | ผ่าน |
| P-07 | จำกัดคำขอ LLM พร้อมกัน + retry | ไม่ล้มเมื่อ provider ตอบ 429/5xx | withLlmSlot (ค่าเริ่มต้น 4 ช่อง LLM_MAX_CONCURRENT), fetchWithRetry exponential backoff | ผ่าน |
| P-08 | ขนาด prompt ไม่เกินเพดาน | ≤10,000 (Q&A) / ≤50,000 (Dhamma Talk) tokens (ก.4.2.1) | fitContext() + tests/unit/graph.test.ts | ผ่าน |
| P-09 | ดัชนีค้นหาอัปเดตแบบ incremental | ไม่ rebuild ทั้งดัชนีเมื่อเพิ่มเอกสาร | Bm25Index.add/remove, reindexDocument() | ผ่าน |
| P-10 | ฐานข้อมูลมีดัชนีบนคอลัมน์ที่ค้นบ่อย | — | @@index ใน prisma/schema.prisma (TokenUsage.createdAt, AuditLog.timestamp, Chunk.volume+item ฯลฯ) | ผ่าน |
| P-11 | ฟอนต์โหลดแบบไม่บล็อก | display: swap | next/font/google (Kanit, Prompt, Noto Serif Thai) ใน src/app/[locale]/layout.tsx | ผ่าน |
| P-12 | Availability | ≥95%/เดือน (12.1, ก.1.6.1) | uptime ของ process + ช่วง 5xx → SLA report | บางส่วน (วัดจาก session สาธิต) |
| P-13 | Auto Scaling | HPA ตาม CPU 70% (ก.1.6.2) | infra/helm/mbu-buddhist-ai/templates/hpa.yaml | ต้องทำบน Production |
2. Checklist ด้านความมั่นคงปลอดภัย (Security)
| # | รายการตรวจ | วิธีตรวจ/หลักฐาน | สถานะ |
|---|---|---|---|
| S-01 | Server-side input validation ทุก endpoint (ก.2.1.3) | zod schema ใน withApi({ body, query }); ค่าไม่ถูกต้อง → 400 | ผ่าน |
| S-02 | ป้องกัน SQL Injection | Prisma (parameterized query); ไม่มี raw SQL จาก input ผู้ใช้ | ผ่าน |
| S-03 | ป้องกัน XSS | React escape อัตโนมัติ; Markdown แสดงด้วย react-markdown (ไม่เปิด raw HTML); CSP script-src 'self' 'unsafe-inline' | บางส่วน — CSP ยังอนุญาต 'unsafe-inline' (ควรเปลี่ยนเป็น nonce บน Production) |
| S-04 | CSRF token (ก.2.1.5) | double-submit cookie + header x-csrf-token ใน src/middleware.ts; tests/api/rbac-ip-allowlist.test.ts | ผ่าน |
| S-05 | Brute force protection (ก.2.1.4) | lockout 5 ครั้ง/15 นาที/บัญชี, 20 ครั้ง/IP; rate limit login 10/นาที | ผ่าน |
| S-06 | Rate limit ระดับแอป | เขียน 60/นาที, อ่าน 600/นาที ต่อ IP (in-memory) | ผ่าน (Production ควรย้ายไป Redis/Ingress) |
| S-07 | การเก็บรหัสผ่าน | bcrypt cost 10 | ผ่าน |
| S-08 | นโยบายรหัสผ่านผู้ดูแล (ก.6.1.4) | ≥12 ตัว ผสม 4 ชนิด (password-policy.ts) | ผ่าน |
| S-09 | Session | JWT HS256 อายุ 24 ชม. ใน cookie HttpOnly; SameSite=Lax (+Secure เมื่อ base URL เป็น https) | ผ่าน |
| S-10 | RBAC + IP allowlist ส่วนผู้ดูแล | withApi({ auth }), ADMIN_IP_ALLOWLIST ใน middleware + audit การปฏิเสธ | ผ่าน — ข้อสังเกต: IP อ่านจาก x-forwarded-for (src/server/security/ip.ts) จึงต้องวางหลัง proxy/Ingress ที่เขียน header ทับเสมอ มิฉะนั้นอาจปลอม header ได้ |
| S-11 | ป้องกัน IDOR | บทสนทนาที่ไม่ใช่ของตน → 404 (tests/api/chat-qa.test.ts) | ผ่าน |
| S-12 | Security headers | CSP, X-Frame-Options DENY, X-Content-Type-Options nosniff, Referrer-Policy, Permissions-Policy, COOP, ปิด X-Powered-By (next.config.ts) | ผ่าน |
| S-13 | HSTS | เปิดเมื่อ ENABLE_HSTS=1 (ตั้งใน .env.production) | บางส่วน (ต้องใช้กับ HTTPS จริง) |
| S-14 | TLS (ก.2.1.2) | self-signed ผ่าน server.https.js (:3443); Production ใช้ cert-manager ที่ Ingress | บางส่วน |
| S-15 | การเข้ารหัสข้อมูลส่วนบุคคล at rest (14.3) | AES-256-GCM คอลัมน์อีเมล/ชื่อ (src/server/crypto.ts) | ผ่าน (ไฟล์ SQLite ทั้งไฟล์ไม่ได้เข้ารหัส) |
| S-16 | ปิดบัง PII ในสำเนาบทสนทนา | maskPii() → Message.contentMasked | ผ่าน |
| S-17 | ข้อความผิดพลาดไม่เปิดเผยรายละเอียดภายใน | withApi ตอบ INTERNAL_ERROR ทั่วไป; stack trace อยู่ใน log เท่านั้น | ผ่าน |
| S-18 | Logging และ Audit trail | JSON log + ApiRequestLog + AuditLog append-only (trigger) + hash chain | ผ่าน |
| S-19 | การจัดการความลับ | .env ไม่อยู่ใน repository; API ไม่คืนค่าคีย์; Production ใช้ Kubernetes Secret | ผ่าน |
| S-20 | Vulnerability scan dependency (ก.2.2.2, 4.8.1) | npm run report:security (npm audit) → /documents/vulnerability-scan-report; CI fail เมื่อ High/Critical | ผ่าน (ดูตัวเลขในรายงาน) |
| S-21 | Penetration test (4.8.2) | — | ยังไม่ทำ — ไม่ได้ดำเนินการในรอบนี้ตามคำสั่งของผู้ว่าจ้าง (/documents/pentest-report) |
| S-22 | WAF / Anti-DDoS (ก.2.2.1) | ตัวอย่าง annotation ใน infra/helm/mbu-buddhist-ai/values.yaml | ต้องทำบน Production |
| S-23 | อัปโหลดไฟล์ปลอดภัย | จำกัดนามสกุล pdf/txt/md/xml/docx, ≤20MB, เก็บนอก public, parse ฝั่งเซิร์ฟเวอร์ | ผ่าน (ยังไม่มีการสแกนมัลแวร์) |
| S-24 | Container hardening (Production) | runAsNonRoot, readOnlyRootFilesystem, drop ALL capabilities, seccomp RuntimeDefault (Helm values) | ต้องทำบน Production |
| S-25 | สำรองและกู้คืน (ก.1.6.3) | scripts/backup-db.sh, restore-db.sh, restore-test.sh → /documents/restore-test-report | ผ่าน |
2.1 ความปลอดภัยเฉพาะ AI (OWASP Top 10 for LLM / Agentic)
| # | ความเสี่ยง | มาตรการในระบบ | สถานะ |
|---|---|---|---|
| AI-01 | Prompt injection ทางตรง | injection_pattern ใน guardrail + guard-classifier (LLM จริง) | ผ่าน — วัดด้วยชุด INJ 20 เคส (/documents/guardrail-security-report) |
| AI-02 | Indirect injection ผ่านเอกสาร | sanitize ตอนนำเข้า + delimiter <<<DATA>>> | ผ่าน |
| AI-03 | Sensitive information disclosure (system prompt) | รูปแบบ “เปิดเผย prompt/system prompt” ถูกปฏิเสธ; /api/status ไม่คืนความลับ | ผ่าน |
| AI-04 | Improper output handling | คำตอบ render เป็น Markdown ไม่รัน HTML; citation ที่ไม่อยู่ในรายการอ้างอิงถูกตัด | ผ่าน |
| AI-05 | Unbounded consumption / cost surge | เพดาน 24 ชม., per-prompt cap, input.maxChars, thinking budget, auto unavailable, แจ้งเตือน | ผ่าน |
| AI-06 | Misinformation / hallucination | บังคับอ้างอิงทุกย่อหน้า + ป้าย “ไม่มีอ้างอิง — โปรดตรวจสอบ” + ข้อความเตือน + วัดด้วย Benchmark | บางส่วน (ขึ้นกับผลประเมิน) |
| AI-07 | Excessive agency | Agent ไม่มีเครื่องมือเขียนข้อมูล/เรียกระบบภายนอก นอกจากค้นคลังความรู้ | ผ่าน |
| AI-08 | หัวข้ออ่อนไหว (การเมือง ศาสนา สุขภาพจิต) | refuse_sensitive + วัดด้วย GR-2 | ผ่าน (ดูผลในรายงาน) |
3. การประเมินตนเองตามมาตรฐานเว็บไซต์ภาครัฐ เวอร์ชัน 3.0 (ก.1.1.1)
ประเมินตามหมวดหลักของมาตรฐาน (การจัดกลุ่มด้านล่างเป็นการสรุปของผู้รับจ้าง) — สถานะใน /tor: partial
| หมวด | ประเด็น | หลักฐานในระบบ | สถานะ |
|---|---|---|---|
| ข้อมูลหน่วยงาน | ชื่อหน่วยงาน ตราสัญลักษณ์ ที่อยู่ ช่องทางติดต่อ | Header มีโลโก้ มมร. (alt text), Footer มีที่อยู่ตาม TOR ข้อ 17 และโทรศัพท์, หน้า /help | ผ่าน |
| การเข้าถึงได้ (Accessibility) | contrast, ข้อความทดแทนรูป, ภาษาของหน้า, ข้ามไปเนื้อหา, ใช้งานด้วยแป้นพิมพ์ | contrast.test.ts, alt ของโลโก้, <html lang={locale}>, ลิงก์ “ข้ามไปยังเนื้อหา” (Header), ปุ่มมี aria-* บางส่วน | บางส่วน — ยังไม่ได้ตรวจ WCAG ครบทุกเกณฑ์ด้วยเครื่องมือ/ผู้ใช้จริง |
| การรองรับอุปกรณ์ | Responsive มือถือ/แท็บเล็ต/เดสก์ท็อป | Playwright 390/768/1280 ไม่มี horizontal scroll | ผ่าน (Chromium) |
| หลายภาษา | ไทย/อังกฤษ | next-intl /th /en + ตรวจ key ครบ | ผ่าน |
| ความเป็นส่วนตัว | นโยบายความเป็นส่วนตัว, ความยินยอมคุกกี้ | /privacy-policy, แบนเนอร์คุกกี้ (ปฏิเสธได้), GA โหลดหลังยินยอม | ผ่าน |
| ความปลอดภัย | HTTPS, การยืนยันตัวตน, การป้องกันการโจมตีพื้นฐาน | หัวข้อ 2 | บางส่วน (TLS จริงต้องบน Production) |
| การบริหารเนื้อหา | วันที่ปรับปรุง, เวอร์ชันระบบ | Footer แสดงเวอร์ชันระบบและ prompt version; วันที่แสดงเป็น พ.ศ. | บางส่วน |
| การค้นหาและนำทาง | เมนูชัดเจน, แผนผังเว็บไซต์ | เมนูหลักใน Header; ไม่มีหน้า sitemap/robots.txt | บางส่วน — ควรเพิ่ม sitemap.xml และ robots.txt |
| สถิติการใช้งาน | เครื่องมือวัดผล | GA4 (NEXT_PUBLIC_GA_ID) + Dashboard ภายใน | ผ่าน (เมื่อมหาวิทยาลัยใส่ GA ID) |
| โดเมนภาครัฐ | ใช้โดเมน .ac.th ของหน่วยงาน | กำหนด dhammaverse.mbu.ac.th ใน Ingress | ต้องทำบน Production (DNS ยังไม่ resolve) |
4. การประเมินตนเองตามมาตรฐานความมั่นคงปลอดภัยเว็บไซต์ พ.ศ. 2568 (ก.1.1.2)
จัดกลุ่มตามประเด็นหลักด้านการรักษาความมั่นคงปลอดภัยเว็บไซต์ (การจัดกลุ่มเป็นของผู้รับจ้าง) — สถานะใน /tor: partial
| ประเด็น | หลักฐาน | สถานะ |
|---|---|---|
| การเข้ารหัสการสื่อสาร (HTTPS/TLS, HSTS) | S-13, S-14 | บางส่วน |
| การยืนยันตัวตนและการจัดการเซสชัน | S-05, S-07–S-09 | ผ่าน |
| การควบคุมการเข้าถึง (RBAC, ส่วนผู้ดูแลจำกัด IP) | S-10, S-11 | ผ่าน |
| การตรวจสอบข้อมูลนำเข้าและป้องกันการโจมตีเว็บ (SQLi, XSS, CSRF) | S-01–S-04 | ผ่าน (มีข้อสังเกต CSP) |
| HTTP security headers | S-12 | ผ่าน |
| การบันทึกเหตุการณ์และการตรวจสอบย้อนหลัง | S-18 | ผ่าน |
| การจัดการช่องโหว่และอัปเดตซอฟต์แวร์ | S-20 (npm audit ใน CI) | ผ่าน |
| การทดสอบเจาะระบบ | S-21 | ยังไม่ทำ (ตามคำสั่งผู้ว่าจ้าง) |
| การป้องกัน DDoS/WAF | S-22 | ต้องทำบน Production |
| การสำรองข้อมูลและกู้คืน | S-25 | ผ่าน |
| การคุ้มครองข้อมูลส่วนบุคคล | S-15, S-16, PDPA self-service | ผ่าน |
5. การประเมินตนเองตาม OWASP Top 10 (2021)
| รหัส | หมวด | มาตรการ | สถานะ |
|---|---|---|---|
| A01 | Broken Access Control | RBAC ทุก endpoint, IP allowlist, ownership check (IDOR → 404), SUPER_ADMIN-only สำหรับ backup/destruction/role | ผ่าน (ทดสอบใน AT-01, AT-07, AT-22, E2E-25) |
| A02 | Cryptographic Failures | bcrypt, AES-256-GCM สำหรับ PII, JWT HS256 (AUTH_SECRET), TLS | บางส่วน (TLS จริงบน Production) |
| A03 | Injection | zod + Prisma; prompt injection guardrail | ผ่าน |
| A04 | Insecure Design | Clean architecture, threat model เฉพาะ AI (หัวข้อ 2.1), token budget | ผ่าน |
| A05 | Security Misconfiguration | security headers, ปิด X-Powered-By, ค่าเริ่มต้นของ AUTH_SECRET ใน session.ts ใช้เฉพาะเมื่อไม่ได้ตั้งค่า (Production ต้องตั้งเสมอ), CSP ยังมี 'unsafe-inline' | บางส่วน |
| A06 | Vulnerable and Outdated Components | npm audit (CI gate --audit-level=high) | ผ่าน (ดู /documents/vulnerability-scan-report) |
| A07 | Identification and Authentication Failures | lockout, rate limit, นโยบายรหัสผ่าน, OAuth state/PKCE | ผ่าน |
| A08 | Software and Data Integrity Failures | npm ci + lockfile ใน CI, AuditLog hash chain, sanitize เอกสารนำเข้า | ผ่าน |
| A09 | Security Logging and Monitoring Failures | AuditLog, ApiRequestLog, app.log, แจ้งเตือน error rate | ผ่าน |
| A10 | Server-Side Request Forgery | ระบบเรียก URL ภายนอกเฉพาะที่กำหนดใน env (LLM, TEI, OAuth, SMTP) ผู้ใช้กำหนด URL ไม่ได้ | ผ่าน |
ข้อสังเกตที่ควรแก้ก่อนใช้งานจริง: (1) CSP แบบ nonce แทน
'unsafe-inline'(2) ย้าย rate limit ไป Redis/Ingress (3) เปิด HSTS + TLS จริง (4) ดำเนินการ Penetration Test โดยผู้ทดสอบอิสระก่อนเปิดให้บริการ (5) สแกนมัลแวร์ไฟล์อัปโหลด (6) เพิ่ม sitemap/robots
6. รายงานผลที่เกี่ยวข้อง
| รายงาน | คำสั่งสร้าง |
|---|---|
/documents/performance-report | npm run report:perf |
/documents/vulnerability-scan-report | npm run report:security |
/documents/pentest-report | — (บันทึกว่าไม่ได้ดำเนินการในรอบนี้) |
/documents/guardrail-security-report | npm run report:evaluation หรือปุ่มที่ /admin/evaluation/security-report |
/documents/restore-test-report | npm run report:restore-test |
/documents/sla-monthly-report | npm run report:sla |