การบล็อก IP ด้วย PHP

การบล็อกที่อยู่ IP (IP Address) เป็นมาตรการรักษาความปลอดภัยที่จำเป็นสำหรับเว็บไซต์และเว็บแอปพลิเคชัน เพื่อป้องกันการเข้าถึงที่ไม่พึงประสงค์ เช่น การสแปม, การโจมตีแบบ Brute-force, หรือการเข้าถึงจากผู้ใช้ที่ถูกแบน บทความนี้จะแนะนำวิธีการบล็อก IP ด้วยภาษา PHP อย่างละเอียด ตั้งแต่พื้นฐานจนถึงเทคนิคขั้นสูง พร้อมตัวอย่างโค้ดที่นำไปปรับใช้ได้ทันที
การตรวจสอบ IP Address ของผู้ใช้งาน
ก่อนที่จะทำการบล็อก IP เราจำเป็นต้องทราบ IP Address ที่แท้จริงของผู้ใช้งานก่อน โดยปกติแล้วเราสามารถดึงค่า IP ได้จากตัวแปร $_SERVER['REMOTE_ADDR']
แต่ในบางกรณีที่ผู้ใช้งานผ่านพร็อกซี (Proxy) หรือบริการอย่าง Cloudflare ค่า IP ที่ได้อาจจะไม่ใช่ IP ที่แท้จริงของผู้ใช้
เพื่อให้ได้ IP ที่แม่นยำยิ่งขึ้น เราควรตรวจสอบค่าจาก HTTP Headers อื่นๆ ด้วย เช่น HTTP_X_FORWARDED_FOR
หรือ HTTP_CF_CONNECTING_IP
(สำหรับ Cloudflare)
ฟังก์ชันสำหรับตรวจสอบ IP Address ที่แท้จริง
function get_real_ip() {
if (!empty($_SERVER['HTTP_CLIENT_IP'])) {
// IP from shared internet
$ip = $_SERVER['HTTP_CLIENT_IP'];
} elseif (!empty($_SERVER['HTTP_X_FORWARDED_FOR'])) {
// IP pass from proxy
$ip = $_SERVER['HTTP_X_FORWARDED_FOR'];
} elseif (!empty($_SERVER['HTTP_CF_CONNECTING_IP'])) {
// IP from Cloudflare
$ip = $_SERVER['HTTP_CF_CONNECTING_IP'];
} else {
$ip = $_SERVER['REMOTE_ADDR'];
}
return filter_var($ip, FILTER_VALIDATE_IP);
}
$user_ip = get_real_ip();
วิธีการจัดเก็บรายการ IP ที่ต้องการบล็อก
เราสามารถจัดเก็บรายการ IP ที่ต้องการบล็อกได้หลายวิธี ซึ่งแต่ละวิธีก็มีข้อดีและข้อเสียแตกต่างกันไป
1. การใช้ Array ในโค้ดโดยตรง
เป็นวิธีที่ง่ายและรวดเร็วที่สุด เหมาะสำหรับการบล็อก IP จำนวนไม่มาก
ตัวอย่าง:
$blocked_ips = [
'192.168.1.100',
'203.0.113.55'
];
if (in_array($user_ip, $blocked_ips)) {
// ดำเนินการบล็อก
die('Your IP has been blocked.');
}
- ข้อดี ง่าย, ไม่ต้องตั้งค่าเพิ่มเติม
- ข้อเสีย แก้ไขลำบาก ต้องเข้าไปแก้ในโค้ดโดยตรง, ไม่เหมาะกับรายการ IP จำนวนมาก
2. การใช้ไฟล์ Text (.txt)
เป็นวิธีการที่ยืดหยุ่นกว่าการใช้ Array ทำให้สามารถจัดการรายการ IP ได้ง่ายขึ้นโดยไม่ต้องแก้ไขโค้ด
ตัวอย่าง
สร้างไฟล์ blocked_ips.txt
และใส่ IP ที่ต้องการบล็อก บรรทัดละ 1 IP
192.168.1.100
203.0.113.55
10.0.0.1
จากนั้นใช้ PHP อ่านไฟล์นี้:
$blocked_ips_file = 'blocked_ips.txt';
if (file_exists($blocked_ips_file)) {
$blocked_ips = file($blocked_ips_file, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
if (in_array($user_ip, $blocked_ips)) {
// ดำเนินการบล็อก
die('Your IP has been blocked.');
}
}
- ข้อดี จัดการรายการ IP ง่าย, ไม่ต้องแก้ไขโค้ด
- ข้อเสีย ประสิทธิภาพอาจลดลงหากไฟล์มีขนาดใหญ่มาก
3. การใช้ฐานข้อมูล (Database)
เป็นวิธีที่มีประสิทธิภาพและยืดหยุ่นที่สุด เหมาะสำหรับระบบขนาดใหญ่ที่ต้องการการจัดการ IP ที่ซับซ้อน เช่น การบล็อกชั่วคราว หรือการเก็บสถิติ
ตัวอย่าง (ใช้ MySQLi)
$conn = new mysqli("localhost", "username", "password", "database");
if ($conn->connect_error) {
die("Connection failed: " . $conn->connect_error);
}
$stmt = $conn->prepare("SELECT ip_address FROM blocked_ips WHERE ip_address = ?");
$stmt->bind_param("s", $user_ip);
$stmt->execute();
$result = $stmt->get_result();
if ($result->num_rows > 0) {
// ดำเนินการบล็อก
die('Your IP has been blocked.');
}
$stmt->close();
$conn->close();
- ข้อดี มีประสิทธิภาพสูง, ยืดหยุ่น, สามารถต่อยอดฟังก์ชันอื่นๆ ได้
- ข้อเสีย ตั้งค่าซับซ้อนกว่า, ต้องมีระบบฐานข้อมูล
เทคนิคการบล็อก IP ในรูปแบบต่างๆ
นอกจากการบล็อก IP แบบเดี่ยวๆ แล้ว เรายังสามารถบล็อกเป็นช่วง (Range) หรือบล็อกทั้งประเทศได้อีกด้วย
การบล็อก IP เป็นช่วง (IP Range)
เราสามารถใช้สัญลักษณ์ Wildcard (*
) หรือสัญลักษณ์ CIDR (Classless Inter-Domain Routing) เพื่อบล็อก IP เป็นช่วงได้
ตัวอย่างการบล็อกด้วย Wildcard:
$blocked_patterns = [
'192.168.1.*', // บล็อกทุก IP ที่ขึ้นต้นด้วย 192.168.1
'10.0.*.*' // บล็อกทุก IP ที่ขึ้นต้นด้วย 10.0
];
foreach ($blocked_patterns as $pattern) {
$regex = '/^' . str_replace('*', '\d+', $pattern) . '$/';
if (preg_match($regex, $user_ip)) {
die('Your IP range has been blocked.');
}
}
ตัวอย่างการบล็อกด้วย CIDR:
การตรวจสอบ CIDR จะซับซ้อนกว่า แต่ก็มีความแม่นยำสูง
function ip_in_cidr($ip, $cidr) {
list($subnet, $mask) = explode('/', $cidr);
if ((ip2long($ip) & ~((1 << (32 - $mask)) - 1)) == ip2long($subnet)) {
return true;
}
return false;
}
$blocked_cidrs = [
'192.168.1.0/24',
'10.0.0.0/8'
];
foreach ($blocked_cidrs as $cidr) {
if (ip_in_cidr($user_ip, $cidr)) {
die('Your IP range has been blocked.');
}
}
การบล็อกทั้งประเทศ
เราสามารถใช้บริการ GeoIP Database เพื่อระบุประเทศของ IP Address นั้นๆ แล้วทำการบล็อกตามรายชื่อประเทศที่กำหนด มีทั้งบริการฟรีและเสียเงิน เช่น MaxMind GeoLite2
การตอบสนองเมื่อผู้ใช้ถูกบล็อก
เมื่อตรวจพบ IP ที่อยู่ในรายการบล็อก เราควรแสดงผลเพื่อแจ้งให้ผู้ใช้ทราบ แทนที่จะปล่อยให้หน้าเว็บโหลดไม่ขึ้น
1. แสดงหน้าข้อความธรรมดา
เป็นวิธีที่ง่ายที่สุด คือการใช้คำสั่ง die()
หรือ exit()
เพื่อหยุดการทำงานของสคริปต์และแสดงข้อความ
die('Access Denied. Your IP address has been blocked.');
2. แสดงหน้า 403 Forbidden
เป็นวิธีที่เป็นมาตรฐาน โดยการส่ง HTTP Status Code 403 Forbidden กลับไปให้เบราว์เซอร์ ซึ่งจะแสดงหน้าข้อผิดพลาดของเบราว์เซอร์หรือของเซิร์ฟเวอร์
header('HTTP/1.1 403 Forbidden');
die('403 Forbidden');
3. สร้างหน้า 403 แบบกำหนดเอง
เพื่อประสบการณ์ที่ดีของผู้ใช้ เราสามารถสร้างหน้า 403 ของเราเอง เพื่อแสดงข้อความและดีไซน์ที่เป็นมิตรมากขึ้น
header('HTTP/1.1 403 Forbidden');
include('custom_403_page.html');
exit();
การเลือกใช้วิธีการบล็อก IP ที่เหมาะสมขึ้นอยู่กับความต้องการและขนาดของเว็บไซต์ ควรพิจารณาถึงความง่ายในการจัดการและประสิทธิภาพของระบบเป็นหลัก เพื่อให้เว็บไซต์ของคุณปลอดภัยจากการเข้าถึงที่ไม่พึงประสงค์ได้อย่างมีประสิทธิภาพ