基於 IP 的存取控制是基礎安全手段,可封鎖特定 IP、IP 區段 (CIDR) 或僅允許白名單。本文提供完整實作代碼,支援 IPv4 區段判斷。
function getClientIP() {
$headers = [
'HTTP_CLIENT_IP',
'HTTP_X_FORWARDED_FOR',
'HTTP_X_FORWARDED',
'HTTP_X_CLUSTER_CLIENT_IP',
'HTTP_FORWARDED_FOR',
'HTTP_FORWARDED',
'REMOTE_ADDR'
];
foreach ($headers as $header) {
if (!empty($_SERVER[$header])) {
$ips = explode(',', $_SERVER[$header]);
$ip = trim($ips[0]); // 取第一個 (最接近客戶端)
if (filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE)) {
return $ip;
}
}
}
return $_SERVER['REMOTE_ADDR'] ?? '0.0.0.0';
}
function ipInRange($ip, $cidr) {
list($range, $netmask) = explode('/', $cidr, 2);
$rangeDec = ip2long($range);
$ipDec = ip2long($ip);
$maskDec = ~((1 << (32 - $netmask)) - 1);
return ($ipDec & $maskDec) === ($rangeDec & $maskDec);
}
// 使用範例
$blockedRanges = ['192.168.1.0/24', '10.0.0.0/8', '172.16.0.0/12'];
$clientIP = getClientIP();
foreach ($blockedRanges as $range) {
if (ipInRange($clientIP, $range)) {
header('Location: https://example.com/blocked.html');
exit;
}
}
['192.168.1.88'], // 單一 IP
'blocked_ranges' => ['192.168.1.0/24'], // CIDR 區段
'allowed_ips' => [], // 白名單 (空=不限制)
'redirect_url' => 'https://example.com/403.html',
];
$clientIP = getClientIP();
// 白名單優先
if (!empty($config['allowed_ips'])) {
$allowed = false;
foreach ($config['allowed_ips'] as $allow) {
if (strpos($allow, '/') !== false) {
if (ipInRange($clientIP, $allow)) { $allowed = true; break; }
} elseif ($clientIP === $allow) {
$allowed = true; break;
}
}
if (!$allowed) { redirectBlock(); }
}
// 黑名單檢查
foreach ($config['blocked_ips'] as $ip) {
if ($clientIP === $ip) { redirectBlock(); }
}
foreach ($config['blocked_ranges'] as $range) {
if (ipInRange($clientIP, $range)) { redirectBlock(); }
}
function redirectBlock() {
global $config;
header('Location: ' . $config['redirect_url']);
exit;
}
function getClientIP() { /* 同上 */ }
function ipInRange($ip, $cidr) { /* 同上 */ }
?>
// 產生表單 Token
function generateFormToken() {
$token = bin2hex(random_bytes(32));
$_SESSION['form_tokens'][$token] = [
'ip' => getClientIP(),
'time' => time(),
'used' => false
];
// 清理過期 token (超過 1 小時)
foreach ($_SESSION['form_tokens'] as $k => $v) {
if (time() - $v['time'] > 3600) unset($_SESSION['form_tokens'][$k]);
}
return $token;
}
// 驗證表單 Token
function verifyFormToken($token) {
if (empty($_SESSION['form_tokens'][$token])) return false;
$data = $_SESSION['form_tokens'][$token];
if ($data['used']) return false; // 防重放
if ($data['ip'] !== getClientIP()) return false; // IP 綁定
if (time() - $data['time'] > 3600) return false; // 過期
$_SESSION['form_tokens'][$token]['used'] = true;
return true;
}
| 層級 | 建議位置 | 優點 |
|---|---|---|
| Web Server | Nginx deny 192.168.1.0/24; / Apache Require not ip 192.168.1 | 效能最好、PHP 不啟動 |
| PHP 入口 | auto_prepend_file 或框架中介層 | 全域生效、易維護 |
| 應用業務 | 敏感 Controller (登入、付款、刪除) | 精細控制、結合業務邏輯 |
注意:IP 可偽造 (代理、VPN、Tor)、NAT 環境下多用戶共用 IP。IP 封鎖僅為輔助手段,**核心安全仍須依賴認證授權、CSRF Token、速率限制、行為分析** 等多層防護。
此實作提供可直接部署的 IP 區段封鎖與表單 Token 綁定機制,適合快速整合至現有 PHP 專案。