首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 網頁程式設計 >> PHP 程式設計 >> PHP 相關知識

PHP IP 封鎖實作指南:單一 IP、CIDR 區段、效能優化與安全考量

     編輯:PHP 相關知識

專案常需封鎖惡意 IP 或特定區段。單純字串比對 (stripos) 存在誤判(如 1.2.3.4 會誤擋 11.2.3.4)且效能差。本文提供三層次解決方案:簡易版、CIDR 精確版、生產級 Redis 快取版,並分析效能與安全性。

方案一:簡易精確比對(適用小規模)

// ban.txt 每行一個 IP
$banList = file('ban.txt', FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
$banSet = array_flip($banList); // O(1) 查找

$clientIp = $_SERVER['REMOTE_ADDR'] ?? '0.0.0.0';

if (isset($banSet[$clientIp])) {
    http_response_code(403);
    exit("Access denied: Your IP ($clientIp) is banned.");
}

方案二:CIDR 區段支援(標準做法)

/**
 * 檢查 IP 是否在任一 CIDR 區段內
 * @param string $ip      客戶端 IP
 * @param array  $cidrs   如 ['192.168.1.0/24', '10.0.0.0/8']
 * @return bool
 */
function ipInCidrs(string $ip, array $cidrs): bool
{
    // IPv4 轉整數
    $ipLong = ip2long($ip);
    if ($ipLong === false) return false; // 無效 IP

    foreach ($cidrs as $cidr) {
        [$range, $bits] = explode('/', $cidr);
        $mask = ~((1 << (32 - $bits)) - 1);
        $net = ip2long($range) & $mask;
        if (($ipLong & $mask) === $net) {
            return true;
        }
    }
    return false;
}

// 使用範例
$cidrs = [
    '192.168.1.0/24',   // 封鎖整個 192.168.1.x
    '10.0.0.0/8',       // 封鎖 10.x.x.x
    '203.0.113.5/32',   // 封鎖單一 IP (等同 /32)
];

if (ipInCidrs($_SERVER['REMOTE_ADDR'], $cidrs)) {
    http_response_code(403);
    exit('Access denied');
}

方案三:生產級 - Redis Set + Lua 腳本(高併發、動態更新)

// Redis 儲存結構
// Key: ban:ips  (Set)  成員: "192.168.1.100", "10.0.0.0/8"
// Key: ban:cidr_masks  (Hash)  欄位: "8" -> "255.0.0.0", "24" -> "255.255.255.0"  預計算遮罩

// Lua 腳本:原子檢查 IP 是否命中(含 CIDR)
$luaScript = <<connect('127.0.0.1', 6379);
$sha = $redis->script('LOAD', $luaScript);

$clientIp = $_SERVER['REMOTE_ADDR'];
$banned = $redis->evalSha($sha, 2, 'ban:ips', 'ban:cidr_masks', $clientIp);

if ($banned) {
    http_response_code(403);
    exit('Access denied');
}

關鍵安全與效能考量

議題風險對策
代理/負載平衡器後取得真實 IPREMOTE_ADDR 為代理 IP信任代理標頭:$_SERVER['HTTP_X_FORWARDED_FOR'](需驗證代理鏈)
IPv6 支援ip2long 僅支援 IPv4使用 inet_pton() + 128-bit 整數或直接字串比對 CIDR
封鎖清單動態更新檔案讀取需重啟進程或重新 requireRedis 方案支援熱更新;檔案方案用 clearstatcache() + 定時重載
大量 CIDR 規則效能PHP 迴圈檢查慢Lua 腳本在 Redis 內原子執行,微秒級延遲
誤封合法使用者無審核機制加入白名單優先檢查、記錄封鎖日誌供稽核

快速部署清單

  1. 決定封鎖粒度:單一 IP → 方案一;區段 → 方案二;高併發/動態 → 方案三。
  2. 在 Web 伺服器層(Nginx deny、Apache Require not ip)優先攔截,減少 PHP 執行開銷。
  3. 記錄被封鎖請求的 IP、UA、URL、時間,便於事後分析。
  4. 定期審查封鎖清單,移除誤判或過期規則。

IP 封鎖看似簡單,但涉及網路拓撲、協定細節、效能權衡。選對層級、用對資料結構,才能在不犧牲效能的前提下精準防護。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved