ข้ามไปยังเนื้อหา

Security & Performance

ทุกบทเรียนที่ผ่านมาล้วนยกย่องความยืดหยุ่นของ GraphQL: endpoint เดียว, graph ที่มี type กำกับ, และ client ที่ขอ field เฉพาะ ที่ต้องการได้พอดี ความยืดหยุ่นเดียวกันนี้เองคือเหตุผลที่ GraphQL ต้องมีคู่มือด้าน security และ performance เป็นของตัวเอง ฟีเจอร์ที่ทำให้ทีม front-end หลงรัก — “ขออะไรก็ได้ที่เข้าถึงได้” — ก็เป็นคำเชิญที่เปิดกว้างให้ใครก็ตามที่อยากขอ มากเกินไป เช่นกัน

REST API กระจาย API surface ออกไปตาม URL ตายตัวจำนวนมาก แต่ละ URL ทำงานเล็ก ๆ ที่คาดเดาได้ ส่วน GraphQL API ยุบทั้งหมดเหลือ endpoint เดียวที่รับ query อะไรก็ได้ที่ client เขียนขึ้นเอง พลังกับความเสี่ยงจึงเป็นสองด้านของเหรียญเดียวกัน:

  • Power — client ประกอบรูปทรงของ response ที่ต้องการได้แม่นยำใน round trip เดียว โดยเดินผ่านความสัมพันธ์ที่ server ไม่เคยต้องคาดการณ์ล่วงหน้า
  • Risk — client (หรือผู้โจมตี) สามารถประกอบ query ที่ server ก็ ไม่เคยคาดการณ์ไว้เช่นกัน: ซ้อนลึกมาก, ใช้ alias อย่างบ้าคลั่ง, หรือแตกกระจายออกไปเป็น database call นับพันครั้งจากคำขอเดียวที่ดูไร้พิษภัย

เพราะ server ไม่มีทางรู้ล่วงหน้าว่าจะเจอ query แบบไหน จึงต้องวิเคราะห์ cost, identity และ trust ราย request แบบ dynamic นั่นคือภารกิจทั้งหมดของโมดูลนี้

การทำให้ GraphQL API ปลอดภัยและจูนได้ สรุปเหลือคำถามสี่ข้อที่วนกลับมาเสมอ จำสี่ข้อนี้ไว้ แล้วที่เหลือของโมดูลก็เป็นแค่รายละเอียด:

  1. ใครเป็นคนถาม? — สร้าง identity ครั้งเดียวต่อ request นี่คือ authentication ที่ควรอยู่ใน context ของ request ไม่ใช่ใน schema
  2. เขาได้รับอนุญาตไหม? — ตัดสินทีละ field ทีละ type ว่า identity นี้เห็นข้อมูลนี้ได้หรือไม่ นี่คือ authorization ที่อยู่ใน resolver, directive หรือ middleware
  3. query นี้แพงแค่ไหน? — request เดียวจะถูกหรือจะหายนะก็ได้ Depth limiting และ complexity (cost) analysis ปฏิเสธ query ที่แพงเกินไปตั้งแต่ ก่อน รัน
  4. เราเคยเห็นสิ่งนี้มาก่อนไหม?persisted queries, caching, และ rate limiting เปลี่ยนงานที่ทำซ้ำให้กลายเป็นงานที่ถูกและคาดเดาได้ พร้อมทั้งลดพื้นผิวการโจมตีลง
flowchart LR
  Q["Client query"] --> A["Authenticate: who is asking? (context)"]
  A --> Z["Authorize: are they allowed? (resolvers)"]
  Z --> C["Cost check: depth & complexity limits"]
  C --> X["Execute resolvers"]
  X --> D["Data sources"]
  X --> R["Response (cacheable, rate-limited)"]
  C -.->|"too deep / too costly"| Rej["Reject before execution"]
คำขอผ่านการตรวจ identity, permission, และ cost ก่อนที่ resolver จะแตะข้อมูลใด ๆ

นี่คือโมดูล security และ performance ของคอร์ส เมื่อจบโมดูลนี้คุณจะสามารถล็อก GraphQL API ให้แน่นหนาได้โดยไม่ต้องเสียสละความสะดวกที่ทำให้คุณเลือกใช้ GraphQL ตั้งแต่แรก ห้าบทเรียนคือ:

  1. Security & Performance (คุณอยู่ที่นี่) — พื้นผิวของ threat และ cost ของ endpoint เดียวที่ยืดหยุ่น
  2. Authentication & Context — resolve current user ครั้งเดียวต่อ request จาก token และเหตุผลที่ context คือที่อยู่ที่เหมาะที่สุด
  3. Authorization — การตรวจ permission ระดับ field และ type และทางเลือกระหว่างการคืน null กับการ throw forbidden error
  4. Depth & Complexity — การปฏิเสธ query ที่ลึก, ใช้ alias, หรือแพง ด้วย depth limit, cost analysis, และ timeout
  5. Persisted Queries & Caching — การทำ allowlist ของ operation, automatic persisted queries, response และ per-field caching, และ rate limiting

ตลอดทั้งโมดูล in-browser runner จะรัน logic ที่เกี่ยวกับ security จริง ๆ — resolver ที่อ่าน context ที่ authenticate แล้ว, field ที่ปฏิเสธผู้ใช้ที่ไม่ได้รับอนุญาต, และฟังก์ชันที่วัด depth ของ query ที่ parse แล้ว — เพื่อให้คุณได้เห็นกลไกทำงานจริงแทนที่จะต้องเชื่อโดยไม่มีหลักฐาน

ทำไม GraphQL endpoint เดียวจึงต้องมีคู่มือ security เป็นของตัวเองเมื่อเทียบกับ REST API?
คำถามสี่ข้อใดที่สรุปการทำให้ GraphQL API ปลอดภัยและปรับจูนได้?
ในประโยคเดียว อะไรที่ทำให้ความยืดหยุ่นของ GraphQL กลายเป็นความเสี่ยง?