FileEditViewTerminal
IT Issue Bootcamp - Visual Studio Code
day-5-hour-4.mdx

Day 5 / Hour 4

Security, LLM-Safe Coding, and Final Demo

OWASP mapping, deployment checks, LLM-safe workflow, security checklist, and final demo.

60 minutes
Learners can explain CRUD, auth, role, RLS, deploy, and security risks.

Security, LLM-Safe Coding, and Final Demo

Day 5 - ชั่วโมงที่ 4: ตรวจความปลอดภัยและเตรียม Final Demo

เป้าหมายของชั่วโมงนี้

หลังเรียนจบ คุณจะสามารถ:

  1. อธิบายได้ว่า request เดินทางจากหน้าเว็บไปถึง database อย่างไร
  2. เชื่อมความเสี่ยงจาก OWASP กับ Issue Tracker ได้
  3. ตรวจโค้ดจาก AI ก่อนนำมาใช้จริงได้
  4. ตรวจระบบบน Production ด้วย USER และ ADMIN ได้
  5. สาธิต project พร้อมอธิบายเหตุผลของ code ที่เขียนได้

สิ่งที่ใช้

โค้ด Issue Tracker ที่ทำเสร็จแล้ว
Supabase Dashboard
Vercel Dashboard และ Production URL

ชั่วโมงนี้จะไม่เพิ่ม feature ใหม่ แต่จะตรวจว่าระบบที่สร้างมาทำงานครบและปลอดภัยตามขอบเขตของ project


Slide 1: ทบทวนสิ่งที่ทำใน Hour 3

ชั่วโมงที่แล้วเราเพิ่ม Authorization เพื่อให้ผู้ใช้แต่ละคนทำสิ่งต่างกันตาม role:

ส่วนที่เพิ่มหน้าที่
profilesเก็บ role USER และ ADMIN
created_byบอกว่า issue เป็นของผู้ใช้คนใด
RLS Policiesให้ USER เห็นและสร้าง issue ของตัวเอง ส่วน ADMIN เห็นทั้งหมดและเปลี่ยน status ได้
requireUser()ป้องกันหน้าที่ต้อง Login
requireAdmin()ป้องกันหน้าและ Server Action สำหรับ ADMIN
canManageแสดงเครื่องมือจัดการเฉพาะหน้าที่อนุญาต

ตอนนี้ระบบจึงไม่ได้รู้แค่ว่า ใคร Login อยู่ แต่รู้ด้วยว่า คนนั้นทำอะไรกับข้อมูลใดได้บ้าง

ใน Hour 4 เราจะนำระบบที่ทำงานแล้วมาตรวจอีกครั้งว่าแต่ละชั้นปลอดภัย ใช้งานบน Production ได้ และพร้อมสำหรับ Final Demo


Slide 2: ระบบทำงานได้ ยังไม่แปลว่าปลอดภัย

ก่อนให้ request ทำงานต่อ ระบบควรตอบคำถามเหล่านี้:

ใครกำลังใช้งาน?          → Authentication
เขาทำสิ่งนี้ได้หรือไม่?   → Authorization
ข้อมูลมีรูปแบบถูกต้องไหม? → Validation
เขาเข้าถึง row นี้ได้ไหม? → RLS
ถ้าล้มเหลว เรารู้สาเหตุไหม? → Error handling และ Logs

ตัวอย่าง: USER ไม่เห็นปุ่มเปลี่ยน status ไม่ได้แปลว่าปลอดภัย เพราะผู้ใช้อาจส่ง request เองได้

ระบบจึงต้องตรวจ requireAdmin() ใน Server Action และให้ RLS ตรวจสิทธิ์ซ้ำที่ database


Slide 3: รู้จัก OWASP ผ่าน Issue Tracker

OWASP Top 10 คือรายการความเสี่ยงสำคัญของเว็บ ใช้เป็นแนวทางช่วยตั้งคำถามกับระบบ ไม่ใช่สิ่งที่ต้องท่องจำทุกข้อ

ความเสี่ยงถ้าเกิดใน Issue Tracker จะเป็นอย่างไร
Broken Access ControlUSER เปิดหน้า Admin หรือแก้ issue ของคนอื่นได้
Security Misconfigurationยังมี demo policy หรือเปิดสิทธิ์ anon ทิ้งไว้
Software Supply Chain Failuresติดตั้ง package ที่ไม่รู้จักหรือล้าสมัย
Injectionนำข้อความจากผู้ใช้ไปต่อเป็น SQL string โดยตรง
Authentication Failuresเชื่อว่า Login แล้วทุกคนเป็น ADMIN
Mishandling of Exceptional Conditionsกลืน error หรือแสดงรายละเอียดระบบบนหน้าเว็บ

เวลา review code ให้ถามว่า “ผู้ใช้ควบคุมค่าอะไรได้ และระบบตรวจค่านั้นที่ชั้นไหน”


Slide 4: ทำไมต้องป้องกัน Broken Access Control หลายชั้น

Broken Access Control คือการที่ผู้ใช้ทำสิ่งที่ตัวเองไม่มีสิทธิ์ แม้จะ Login สำเร็จแล้วก็ตาม

UI            → ซ่อนลิงก์ Admin และปุ่มเปลี่ยน status จาก USER
Page Guard    → ป้องกันการพิมพ์ /admin/issues โดยตรง
Server Action → ป้องกัน request ที่สร้างขึ้นเอง
RLS           → ป้องกัน operation และ row ที่ database

ลองตรวจด้วย USER

  1. เปิด /admin/issues โดยตรง → ต้องกลับไป /issues
  2. เปิด issue ของคนอื่น → ต้องไม่เห็นข้อมูล
  3. ส่ง update request เอง → Server Action หรือ RLS ต้องปฏิเสธ

การทดสอบว่า ADMIN ใช้งานได้อย่างเดียวไม่พอ ต้องพิสูจน์ด้วยว่า USER ทำสิ่งที่ไม่ได้รับอนุญาตไม่ได้


Slide 5: Validation กับการป้องกัน Injection ต่างกันอย่างไร

Validation ตรวจว่าข้อมูลเหมาะกับระบบหรือไม่

title ต้องยาวอย่างน้อย 5 ตัวอักษร
description ต้องยาวอย่างน้อย 10 ตัวอักษร
status ต้องเป็น OPEN, IN_PROGRESS หรือ DONE

การป้องกัน Injection แยก code ออกจากข้อมูล

  • ใช้ Supabase client ส่งค่าผ่าน method เช่น .eq() และ .insert()
  • อย่านำ input มาต่อเป็น SQL string เอง
  • React แสดงข้อความเป็น text ตามปกติ อย่าใช้ dangerouslySetInnerHTML กับข้อมูลจากผู้ใช้โดยไม่จำเป็น

Browser validation ช่วยให้กรอก form ง่ายขึ้น แต่ Server Action ยังต้อง validate ซ้ำ เพราะผู้ใช้ส่ง request โดยไม่ผ่าน form ได้

เมื่อเกิด error ให้เก็บรายละเอียดที่จำเป็นไว้ใน server log และแสดงข้อความที่เข้าใจง่ายบนหน้าเว็บ โดยไม่เปิดเผย password, token หรือ secret


Slide 6: ค่าไหนเปิดเผยได้ และค่าไหนต้องเป็น Secret

NEXT_PUBLIC_SUPABASE_URL             → ใช้ใน browser ได้
NEXT_PUBLIC_SUPABASE_PUBLISHABLE_KEY → ใช้ใน browser ได้
service_role key                     → ห้ามส่งไป browser

Publishable key บอกว่าแอปกำลังเชื่อม Supabase project ใด แต่ไม่ได้ให้สิทธิ์ข้าม RLS ความปลอดภัยของข้อมูลจึงขึ้นอยู่กับ GRANT และ policies ที่เราเขียน

ก่อน Push Code

  • .env.local ต้องอยู่ใน .gitignore
  • .env.example มีเฉพาะชื่อ variable และไม่มีค่าจริง
  • ตรวจ git status ก่อน commit
  • ห้ามใส่ password, token หรือ service role key ใน README

ติดตั้งเฉพาะ package ที่รู้ว่าใช้ทำอะไร และตรวจชื่อ package จาก documentation ทางการก่อนรันคำสั่งที่ AI แนะนำ


Slide 7: ใช้ AI ช่วยเขียน Code โดยไม่เชื่อทันที

มอง code จาก AI เหมือน code ที่คัดลอกจากอินเทอร์เน็ต: ใช้เป็นจุดเริ่มต้นได้ แต่ต้องตรวจเองก่อน

1. ให้ AI อธิบายว่า code เปลี่ยนอะไรและทำงานฝั่งไหน
2. เทียบ API กับ documentation ของ version ที่ project ใช้
3. อ่าน diff และตรวจทุกไฟล์ที่เปลี่ยน
4. รัน build และทดสอบ flow จริง
5. ทดสอบข้อมูลผิด, ไม่มี session และไม่มีสิทธิ์

อย่าส่ง .env.local, password, token, API secret หรือข้อมูลส่วนบุคคลให้ AI

ก่อนใช้ code ที่เกี่ยวกับสิทธิ์ ต้องตอบให้ได้ว่า:

  • user และ role ถูกตรวจที่ไหน
  • field ใดมาจาก browser และ field ใดมาจาก session
  • database มี RLS policy รองรับ operation นี้หรือไม่

ถ้ายังอธิบายไม่ได้ แปลว่ายังไม่ควรนำ code นั้นไปใช้จริง


Slide 8: ตรวจ Supabase ก่อนทดสอบ Production

Table issues

  • เปิด RLS
  • มี SELECT, INSERT และ UPDATE policies สำหรับ authenticated
  • ไม่มี demo policy ที่ใช้ using (true) หรือ with check (true)
  • ไม่มีสิทธิ์ anon สำหรับอ่านหรือแก้ข้อมูล

Table profiles

  • เปิด RLS
  • USER อ่านได้เฉพาะ profile ของตัวเอง
  • user@example.com มี role USER
  • admin@example.com มี role ADMIN

สร้าง issue ใหม่ด้วย USER แล้วตรวจว่า created_by ตรงกับ id ของ account นั้น

Table Editor ใช้สิทธิ์ผู้ดูแลและอาจเห็นข้อมูลที่หน้าเว็บมองไม่เห็น ดังนั้นการเห็น row ใน Table Editor ยังไม่ยืนยันว่า SELECT policy ของ USER ทำงานถูกต้อง


Slide 9: Deploy Code ล่าสุดและทดสอบของจริง

ท้าย Hour 3 เรา push code ระบบ Auth และ Authorization แล้ว หาก GitHub เชื่อมกับ Vercel จะเกิด Production Deployment ใหม่

1. เปิด Vercel และตรวจว่า deployment มาจาก commit ล่าสุด
2. รอให้ build สำเร็จ
3. ตรวจ Environment Variables ของ Production
4. เปิด Production URL และทดสอบ USER/ADMIN
5. หากแก้ env vars ต้อง redeploy เพื่อให้ deployment ใหม่อ่านค่า

Flow ที่ต้องผ่านบน Production

  • USER Login → สร้าง issue → เห็นเฉพาะ issue ของตัวเอง
  • USER เปิด /admin/issues → ถูกส่งกลับ /issues
  • ADMIN Login → เห็น issue ทั้งหมด → เปลี่ยน status ได้
  • Logout → protected pages ส่งไป /login

ก่อนส่ง project ให้เพิ่ม Production URL, วิธีรัน และชื่อ environment variables ที่ต้องใช้ไว้ใน README โดยไม่ใส่ค่าจริงหรือ password


Slide 10: เมื่อระบบมีปัญหา ให้หาว่าเสียที่ชั้นไหน

อย่าแก้หลายไฟล์พร้อมกัน ให้เริ่มจากอาการแล้วตรวจชั้นที่เกี่ยวข้อง:

ปุ่มหรือข้อมูลบนหน้าผิด       → ตรวจ props และ conditional UI
กด form แล้วไม่ทำงาน         → ตรวจ Server Action และ server logs
อ่าน/เขียน table ไม่ได้       → ตรวจ Supabase error, GRANT และ RLS
ข้อมูลเข้าแต่หน้า list ว่าง    → ตรวจ created_by, session และ SELECT policy
Local ใช้ได้ Production ไม่ได้ → ตรวจ env vars, deployment และ Supabase project

หลังจากนี้คุณสามารถต่อยอดได้

  • เพิ่ม automated tests สำหรับ USER และ ADMIN
  • เพิ่ม error states ที่ช่วยให้ผู้ใช้แก้ปัญหาได้
  • เพิ่ม pagination และ search เมื่อข้อมูลมากขึ้น
  • เพิ่ม audit log และ monitoring สำหรับการใช้งานจริง

เป้าหมายของหลักสูตรไม่ใช่จำทุก syntax แต่คืออ่าน flow ออก รู้ว่าควรตรวจชั้นไหน และอธิบายเหตุผลของ code ที่นำไปใช้ได้


อ้างอิง