Skip to content
Tayakorn
System Design Handbook

System Design Handbook

Security & Rate Limiting — ปกป้องระบบใน Production

Rate Limiting Algorithms · 429 · Distributed Limiter · Hardening · ▶ ในคลิป 1:55:51 – 2:03:30

ระบบที่เปิดสู่อินเทอร์เน็ตจะเจอทราฟฟิกที่ไม่ได้เชิญเสมอ — bot scrape ข้อมูล, สคริปต์เดารหัสผ่าน, client ที่เขียนพลาดยิงวนไม่หยุด, จนถึง DDoS — Rate Limiting คือด่านแรกของการป้องกัน: จำกัดว่าผู้เรียกหนึ่งราย (ระบุจาก API key, user ID หรือ IP) ส่ง request ได้กี่ครั้งต่อช่วงเวลา เกินแล้วตอบ 429 Too Many Requests พร้อม header Retry-After บอกว่าให้รอกี่วินาที

เหตุผลที่ต้องมีไม่ใช่แค่กันโจมตี: ความเป็นธรรม (ผู้ใช้รายเดียวห้ามกินทรัพยากรทั้งระบบ), ควบคุมต้นทุน (ทุก request มีราคา) และ กันระบบตัวเองพัง (bug ที่ retry ถี่ ๆ ก็ถล่มระบบได้เท่า DDoS)

8.1 วางไว้ตรงไหน

มาตรฐานคือวางที่ API Gateway / Load Balancer — ด่านหน้าสุดก่อนถึงแอป เพื่อตัดทราฟฟิกส่วนเกินตั้งแต่ยังไม่กินทรัพยากรของ service และในระบบ scale-out ตัวนับต้องเก็บใน store กลางอย่าง Redis — ถ้าแต่ละเครื่องนับของตัวเอง ผู้โจมตีที่ถูกกระจายไป 10 เครื่องจะได้โควตา ×10 ฟรี ๆ

8.2 สี่อัลกอริทึมที่ต้องรู้

Fixed Window — ช่องโหว่ตรงรอยต่อนาที 10:00 (โควตา 100)นาที 10:01 (โควตา 100)100 req100 reqยิง 100 ตอน 10:00:59 + อีก 100 ตอน 10:01:01= 200 req ใน 2 วินาที — ถูกกติกาแต่ผิดเจตนา!Sliding Window — หน้าต่างเลื่อนตาม60 วินาทีล่าสุดนับย้อนจาก “ตอนนี้” เสมอไม่มีรอยต่อให้เบิ้ลโควตาแลกกับการเก็บ timestamp มากขึ้นToken Bucket — ยอม burst อย่างมีขอบเขตเติม token คงที่ เช่น 10/วินาที1 request = ใช้ 1 tokenถังเต็มเก็บได้ = burst ที่ยอมให้Leaky Bucket — ไหลออกคงที่เสมอrequest เข้าคิวในถังประมวลผลด้วยอัตราคงที่ถังล้น = ปฏิเสธ request— โหลดขาออกเรียบสนิท
FIG 8.1 สี่อัลกอริทึม: fixed window ง่ายแต่มีช่องโหว่รอยต่อ · sliding window อุดช่องโหว่นั้น · token bucket ยอมพีคสั้น ๆ · leaky bucket บังคับอัตราเรียบ
อัลกอริทึมพฤติกรรมเลือกเมื่อ
Fixed Windowนับต่อช่วงเวลาตายตัว ง่าย+ประหยัดสุดงานภายใน ความเป๊ะไม่วิกฤต
Sliding Windowนับ 60 วิล่าสุดแบบเลื่อนตาม ไม่มีรอยต่อpublic API ที่ต้องแฟร์และแม่น
Token Bucketอัตราเฉลี่ยคงที่ + เผื่อ burst สั้น ๆทราฟฟิกจริงที่มีพีคเป็นช่วง (นิยมสุด — AWS ใช้)
Leaky Bucketขาออกเรียบคงที่ ไม่มี burst เลยระบบปลายทางรับโหลดกระชากไม่ได้

API ที่ดีควรบอกสถานะโควตาให้ client รู้ล่วงหน้าผ่าน response headers:

// ตัวอย่าง headers ที่ GitHub/Stripe ใช้
X-RateLimit-Limit:     100      // โควตาต่อหน้าต่างเวลา
X-RateLimit-Remaining: 4        // เหลือใช้ได้อีกกี่ครั้ง
X-RateLimit-Reset:     1740001  // โควตารีเซ็ตเมื่อไร (unix time)
Retry-After:           30       // (เมื่อโดน 429) รออีกกี่วินาที

🧭 ฝั่ง client ก็มีหน้าที่ — client ที่ดีเมื่อเจอ 429 ต้อง retry แบบ exponential backoff + jitter (รอ 1s → 2s → 4s... บวกสุ่มเล็กน้อย) — ถ้าทุก client retry พร้อมกันเป๊ะ จะเกิด "thundering herd" ถล่มระบบซ้ำเป็นระลอก

8.3 เช็กลิสต์ความปลอดภัยขั้นต่ำของ Production

  • HTTPS ทุกเส้นทาง — รวมถึงภายใน data center (zero-trust)
  • Validate input ทุกจุด — ป้องกัน SQL injection (ใช้ parameterized query เสมอ), XSS
  • เก็บ secret ให้ถูกที่ — secret manager / env vars, ห้าม hardcode ลงโค้ดหรือ git
  • Hash รหัสผ่านด้วย bcrypt/argon2 — ห้ามเก็บ plaintext, ห้ามใช้ MD5/SHA1
  • Least privilege ทุกชั้น — service account ของแอปไม่ควรมีสิทธิ์ DROP TABLE
  • Logging + Monitoring — ตรวจจับ pattern ผิดปกติ (login fail ถี่, ทราฟฟิกพุ่ง) ให้เห็นก่อนเป็นข่าว
  • ชั้นป้องกัน DDoS ระดับ network — ใช้ CDN/WAF (Cloudflare ฯลฯ) รับแรงปะทะแทน origin

สรุปบทที่ 8 — Rate limit ที่ gateway + ตัวนับกลางใน Redis · เลือกอัลกอริทึมตามนิสัยทราฟฟิก: token bucket คือ default ที่ดี, sliding window เมื่อต้องแฟร์เป๊ะ · ตอบ 429 พร้อม Retry-After และ headers บอกโควตา · ความปลอดภัยคือการป้องกันหลายชั้นซ้อนกัน (defense in depth) — ไม่มีชั้นเดียวที่เอาอยู่ทั้งหมด

Read the full book