Skip to main content

เนื้อหาภาษาไทย / Thai content

System guide Content reviewed

การใช้ Rate Limiting

บทความนี้กล่าวถึง Rate Limiting ซึ่งเป็นเทคนิคการจำกัดจำนวนการเข้าถึงเว็บไซต์จาก IP address หรือผู้ใช้งานรายเดียวภายในช่วงเวลาที่กำหนด เพื่อป้องกันการโจมตีต่างๆ...

การใช้ Rate Limiting เพื่อป้องกันการโจมตี

จากบทเรียนที่แล้ว เราได้เรียนรู้เกี่ยวกับการใช้ CAPTCHA เพื่อแยกแยะผู้ใช้งานที่เป็นมนุษย์ออกจากบอท ซึ่งเป็นวิธีการป้องกันการโจมตีรูปแบบหนึ่ง อย่างไรก็ตาม CAPTCHA อาจสร้างประสบการณ์ที่ไม่ดีให้กับผู้ใช้งานจริงได้ ดังนั้นในบทนี้ เราจะมาเรียนรู้วิธีการป้องกันการโจมตีอีกรูปแบบหนึ่งที่เรียกว่า Rate Limiting ซึ่งเป็นเทคนิคที่ช่วยจำกัดจำนวนการเข้าถึงเว็บไซต์จาก IP address เดียวภายในช่วงเวลาที่กำหนด

Rate Limiting คืออะไร?

Rate Limiting คือการควบคุมอัตราการเข้าถึงทรัพยากร (เช่น หน้าเว็บ, API endpoint) โดยการจำกัดจำนวน request ที่อนุญาตจาก IP address หรือผู้ใช้งานรายเดียว ภายในช่วงเวลาที่กำหนด ตัวอย่างเช่น เราอาจกำหนดให้ IP address หนึ่งสามารถส่ง request มายัง API endpoint ได้ไม่เกิน 100 ครั้งต่อนาที หากเกินกว่านั้น ระบบจะปฏิเสธ request ที่เกินมา

ทำไมต้องใช้ Rate Limiting?

  • ป้องกัน Brute-Force Attacks: ช่วยป้องกันการพยายามเข้าสู่ระบบด้วยการเดารหัสผ่านซ้ำๆ
  • ป้องกัน DDoS Attacks (Distributed Denial of Service): แม้จะไม่สามารถป้องกัน DDoS ที่ซับซ้อนได้ทั้งหมด แต่ก็ช่วยลดผลกระทบจาก traffic ที่มากเกินไปได้
  • ป้องกัน Web Scraping: ช่วยป้องกันไม่ให้บอทเข้ามาเก็บข้อมูลจากเว็บไซต์ของเราในปริมาณมากเกินไป
  • ควบคุมการใช้งาน API: ช่วยให้มั่นใจได้ว่า API ของเราจะไม่ถูกใช้งานเกินขีดจำกัด และรักษาประสิทธิภาพของระบบ

หลักการทำงานของ Rate Limiting

โดยทั่วไป Rate Limiting ทำงานโดยการ:

  1. ระบุผู้ใช้งาน: มักจะใช้ IP address เป็นตัวระบุ แต่ก็สามารถใช้ User ID (เมื่อผู้ใช้งาน Login แล้ว) หรือ API Key ได้
  2. เก็บ Request Count: นับจำนวน request ที่ส่งมาจากผู้ใช้งานแต่ละรายในช่วงเวลาที่กำหนด
  3. ตรวจสอบ Request Count: ตรวจสอบว่าจำนวน request เกินขีดจำกัดที่กำหนดไว้หรือไม่
  4. ดำเนินการ: หากจำนวน request เกินขีดจำกัด ให้ปฏิเสธ request หรือดำเนินการอื่นๆ เช่น แสดงข้อความแจ้งเตือน

การเก็บ Request Count

เราสามารถเก็บ Request Count ได้หลายวิธี ขึ้นอยู่กับความต้องการและความซับซ้อนของระบบ:

  • Session: เหมาะสำหรับเว็บไซต์ขนาดเล็กที่ไม่ต้องการความซับซ้อนมากนัก
  • ฐานข้อมูล: เหมาะสำหรับเว็บไซต์ขนาดกลางและใหญ่ที่ต้องการความแม่นยำและความยืดหยุ่นสูง
  • Cache (Redis, Memcached): เหมาะสำหรับเว็บไซต์ที่มี traffic สูง และต้องการประสิทธิภาพในการอ่าน/เขียนข้อมูลที่รวดเร็ว

ตัวอย่างการเก็บ Request Count ใน Session:

<?php
session_start();

$ip_address = $_SERVER['REMOTE_ADDR'];
$request_limit = 100; // กำหนดจำนวน request ที่อนุญาต
$time_window = 60; // กำหนดช่วงเวลา (วินาที)

// สร้าง key สำหรับเก็บข้อมูล request count
$request_key = 'rate_limit_' . $ip_address;

// ตรวจสอบว่ามีการสร้าง session สำหรับ IP address นี้แล้วหรือไม่
if (!isset($_SESSION[$request_key])) {
  $_SESSION[$request_key] = [
    'count' => 0,
    'timestamp' => time()
  ];
}

// ตรวจสอบว่าช่วงเวลาที่กำหนดหมดลงแล้วหรือไม่
if (time() - $_SESSION[$request_key]['timestamp'] > $time_window) {
  // รีเซ็ต request count และ timestamp
  $_SESSION[$request_key]['count'] = 0;
  $_SESSION[$request_key]['timestamp'] = time();
}

// เพิ่ม request count
$_SESSION[$request_key]['count']++;

// ตรวจสอบว่า request count เกินขีดจำกัดหรือไม่
if ($_SESSION[$request_key]['count'] > $request_limit) {
  // ปฏิเสธ request
  http_response_code(429); // Too Many Requests
  echo "Too Many Requests";
  exit;
}

// ดำเนินการตามปกติ
echo "Request Accepted";
?>

คำอธิบาย:

  • เราใช้ $_SERVER['REMOTE_ADDR'] เพื่อดึง IP address ของผู้ใช้งาน
  • เราสร้าง session variable ที่มีชื่อขึ้นต้นด้วย rate_limit_ ตามด้วย IP address เพื่อเก็บ request count และ timestamp
  • เราตรวจสอบว่า request count เกินขีดจำกัดหรือไม่ หากเกิน จะส่ง HTTP status code 429 (Too Many Requests) และแสดงข้อความแจ้งเตือน
  • หากช่วงเวลาที่กำหนดหมดลงแล้ว เราจะรีเซ็ต request count และ timestamp

ตัวอย่างการเก็บ Request Count ในฐานข้อมูล:

<?php
// กำหนดค่าการเชื่อมต่อฐานข้อมูล
$host = 'localhost';
$db = 'your_database';
$user = 'your_user';
$password = 'your_password';

try {
  $pdo = new PDO("mysql:host=$host;dbname=$db", $user, $password);
  $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
} catch (PDOException $e) {
  echo "Connection failed: " . $e->getMessage();
  exit;
}

$ip_address = $_SERVER['REMOTE_ADDR'];
$request_limit = 100;
$time_window = 60;

// ตรวจสอบว่ามี record ของ IP address นี้ในฐานข้อมูลหรือไม่
$stmt = $pdo->prepare("SELECT request_count, last_request_time FROM rate_limit WHERE ip_address = ?");
$stmt->execute([$ip_address]);
$row = $stmt->fetch(PDO::FETCH_ASSOC);

if ($row) {
  $request_count = $row['request_count'];
  $last_request_time = $row['last_request_time'];

  // ตรวจสอบว่าช่วงเวลาที่กำหนดหมดลงแล้วหรือไม่
  if (time() - $last_request_time > $time_window) {
    // รีเซ็ต request count
    $request_count = 0;
  }

  // เพิ่ม request count
  $request_count++;

  // อัปเดตข้อมูลในฐานข้อมูล
  $stmt = $pdo->prepare("UPDATE rate_limit SET request_count = ?, last_request_time = ? WHERE ip_address = ?");
  $stmt->execute([$request_count, time(), $ip_address]);

  // ตรวจสอบว่า request count เกินขีดจำกัดหรือไม่
  if ($request_count > $request_limit) {
    http_response_code(429);
    echo "Too Many Requests";
    exit;
  }
} else {
  // สร้าง record ใหม่สำหรับ IP address นี้
  $stmt = $pdo->prepare("INSERT INTO rate_limit (ip_address, request_count, last_request_time) VALUES (?, ?, ?)");
  $stmt->execute([$ip_address, 1, time()]);
}

// ดำเนินการตามปกติ
echo "Request Accepted";
?>

คำอธิบาย:

  • เราสร้างตาราง rate_limit ในฐานข้อมูลเพื่อเก็บข้อมูล IP address, request count และ last request time
  • เราใช้ Prepared Statements เพื่อป้องกัน SQL Injection
  • เราตรวจสอบว่ามี record ของ IP address นี้ในฐานข้อมูลหรือไม่ หากไม่มี จะสร้าง record ใหม่
  • เราอัปเดต request count และ last request time ในฐานข้อมูล
  • เราตรวจสอบว่า request count เกินขีดจำกัดหรือไม่ หากเกิน จะส่ง HTTP status code 429 (Too Many Requests) และแสดงข้อความแจ้งเตือน

ข้อดีและข้อเสียของการใช้ Session vs. ฐานข้อมูล:

  • Session: ง่ายต่อการใช้งาน ไม่ต้องสร้างตารางในฐานข้อมูล แต่ข้อมูลจะหายไปเมื่อ Session หมดอายุ และไม่เหมาะกับเว็บไซต์ที่มี traffic สูง
  • ฐานข้อมูล: แม่นยำและยืดหยุ่นกว่า สามารถเก็บข้อมูลได้ถาวร แต่ต้องสร้างตารางในฐานข้อมูล และอาจมี overhead มากกว่า

การตรวจสอบ Request Count

การตรวจสอบ Request Count เป็นขั้นตอนสำคัญในการ Rate Limiting เราต้องตรวจสอบว่าจำนวน request ที่ส่งมาจากผู้ใช้งานแต่ละราย เกินขีดจำกัดที่กำหนดไว้หรือไม่ หากเกิน เราจะปฏิเสธ request หรือดำเนินการอื่นๆ

ในตัวอย่างโค้ดด้านบน เราได้ทำการตรวจสอบ Request Count โดยใช้เงื่อนไข if ($_SESSION[$request_key]['count'] > $request_limit) หรือ if ($request_count > $request_limit)

การ Block IP Address

ในบางกรณี เราอาจต้องการ block IP address ที่ส่ง request มามากเกินไปอย่างถาวร เพื่อป้องกันการโจมตีที่รุนแรง

เราสามารถ block IP address ได้หลายวิธี:

  • Firewall: ใช้ Firewall ของระบบปฏิบัติการ (เช่น iptables) หรือ Firewall ของ Web Server (เช่น .htaccess)
  • ฐานข้อมูล: สร้างตารางสำหรับเก็บ IP address ที่ถูก block และตรวจสอบทุกครั้งที่มี request เข้ามา
  • Software เฉพาะทาง: ใช้ software ที่มีความสามารถในการป้องกันการโจมตีโดยเฉพาะ

ตัวอย่างการ Block IP Address โดยใช้ .htaccess:

<Files ~ "\.php$">
  Order Allow,Deny
  Allow from all
  Deny from 192.168.1.100
</Files>

คำอธิบาย:

  • เราใช้ Deny from เพื่อ block IP address 192.168.1.100
  • คำสั่งนี้จะ block การเข้าถึงไฟล์ PHP ทั้งหมดจาก IP address ที่ระบุ

สรุป

Rate Limiting เป็นเครื่องมือที่มีประสิทธิภาพในการป้องกันการโจมตีต่างๆ ที่อาจเกิดขึ้นกับเว็บไซต์ของเรา โดยการจำกัดจำนวน request ที่อนุญาตจาก IP address หรือผู้ใช้งานรายเดียว การเลือกวิธีการเก็บ Request Count และการ Block IP Address ขึ้นอยู่กับความต้องการและความซับซ้อนของระบบ

ในบทเรียนถัดไป เราจะมาเรียนรู้เกี่ยวกับการใช้ Two-Factor Authentication (2FA) เพื่อเพิ่มความปลอดภัยในการเข้าสู่ระบบ

Office.in.th Custom Service

Want to build or adapt a system from this structure?

Office.in.th designs and develops enterprise web applications, API integrations, and public- and private-sector management systems, with long-term support.

See our software development service