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

PHP 緊急防禦:限制 IP 訪問頻率防惡意攻擊

     編輯:PHP 綜合知識

網站遭遇惡意刷新、掃描或 CC 攻擊時,若無現成 WAF 防護,可部署此 PHP 緊急腳本:記錄 IP 訪問頻率,超過閾值自動寫入 .htaccess 封鎖。屬權宜之計,長期仍需完善架構層面防禦。

核心邏輯

  1. 讀取 $_SERVER['REMOTE_ADDR'] 獲取客戶端 IP
  2. 檢查 .htaccess2 黑名單,命中直接 exit
  3. 以檔案記錄各 IP 近期請求時間戳與計數
  4. 超過 $allowtime 秒內 $allownum 次請求 → 記入臨時封鎖檔
  5. 臨時封鎖檔累計達 $allowRefresh 次 → 永久寫入 .htaccess2

完整部署代碼

<?php
header('Content-type: text/html; charset=utf-8');

$ip = $_SERVER['REMOTE_ADDR'];
$logDir = './log/';
$htaccessFile = '.htaccess2';
$allowTime = 60;      // 統計時間窗(秒)
$allowNum = 5;        // 窗口內允許請求數
$allowRefresh = 120;  // 觸發永久封鎖的臨時封鎖次數

// 初始化檔案
foreach ([$htaccessFile, $logDir.'ipdate.dat', $logDir.'forbidchk.dat'] as $f) {
    if (!file_exists($f)) @file_put_contents($f, '');
}
if (!is_dir($logDir)) @mkdir($logDir, 0777);

// 檢查永久黑名單
$banList = @file($htaccessFile, FILE_IGNORE_NEW_LINES);
if (in_array($ip, $banList)) {
    exit('警告:您的 IP 已被永久封鎖!');
}

$now = time();

// === 臨時封鎖檢查 ===
$forbidFile = $logDir . 'forbidchk.dat';
if (file_exists($forbidFile)) {
    if ($now - filemtime($forbidFile) > 30) {
        @unlink($forbidFile); // 過期清理
    } else {
        $arr = @file($forbidFile, FILE_IGNORE_NEW_LINES);
        if ($arr[0] === $ip) {
            if ($now - $arr[1] > 120) {
                @unlink($forbidFile);
            } elseif ($arr[2] > $allowRefresh) {
                file_put_contents($htaccessFile, $ip . PHP_EOL, FILE_APPEND);
                @unlink($forbidFile);
            } else {
                $arr[2]++; file_put_contents($forbidFile, implode(PHP_EOL, $arr));
            }
        }
    }
}

// === 頻率統計與限制 ===
$ipFile = $logDir . 'ipdate.dat';
$records = @file($ipFile, FILE_IGNORE_NEW_LINES);
$newRecords = [];
$allow = true;

foreach ($records as $line) {
    [$recIp, $recUri, $recTime, $recCount] = [
        substr($line, 0, 32),
        substr($line, 32, 32),
        (int)substr($line, 64, 10),
        (int)substr($line, 74)
    ];

    if ($now - $recTime < $allowTime) {
        if ($recIp === md5($ip)) {
            $allow = false;
            $uriHash = md5($_SERVER['REQUEST_URI']);
            if ($recUri !== $uriHash) {
                $newRecords[] = $recIp . $uriHash . $now . "\n";
            } elseif ($recCount < $allowNum) {
                $newRecords[] = $recIp . $recUri . $recTime . ($recCount + 1) . "\n";
            } else {
                // 觸發臨時封鎖
                if (!file_exists($forbidFile)) {
                    file_put_contents($forbidFile, "$ip\n$now\n1\n");
                }
                file_put_contents($logDir . 'forbided_ip.log', "$ip--" . date('Y-m-d H:i:s') . "--{$_SERVER['REQUEST_URI']}\n", FILE_APPEND);
                exit('警告:請勿頻繁刷新!');
            }
        } else {
            $newRecords[] = $line . "\n";
        }
    }
    // 過期記錄自動捨棄
}

if ($allow) {
    $newRecords[] = md5($ip) . md5($_SERVER['REQUEST_URI']) . $now . "1\n";
}
file_put_contents($ipFile, implode('', $newRecords));

關鍵參數調整建議

參數預設值調整建議
$allowTime60 秒靜態資源多則調大,API 介面調小
$allowNum5 次正常瀏覽約 10-30 次/分,視業務調整
$allowRefresh120 次誤傷風險與防禦強度的平衡點

局限性與長期對策

  • 單機檔案鎖競爭:高併發下 flock 可能成為瓶頸,建議改用 Redis 原子計數器
  • 無法防禦分散式攻擊:僅限制單 IP,需結合 WAF、CDN 邊緣防護
  • 誤封風險:企業出口 IP 共用易誤傷,建議加入白名單機制
  • 繞過手段:攻擊者可換 IP、使用代理池,需行為分析而非單純頻率限制

此腳本適用於「被攻擊當下、無現成防護、需快速上線」的緊急場景。長期請部署專業 WAF(如 ModSecurity)、CDN 防護(Cloudflare 等)並建立完整監控告警體系。

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