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

從刷票實戰理解獲取客戶端真實 IP 的方法與偽造防範

     編輯:PHP 綜合知識

三大 IP 獲取來源對比

來源取得方式可信度適用場景
HTTP_X_FORWARDED_FORHTTP 標頭 X-Forwarded-For低(可偽造)負載均衡、代理後端
HTTP_CLIENT_IPHTTP 標頭 Client-Ip低(可偽造)極少使用,不推薦
REMOTE_ADDRTCP 連線來源 IP高(難偽造)直接連線、無代理環境

X-Forwarded-For 格式與風險

X-Forwarded-For: client, proxy1, proxy2
  • 最左側為原始客戶端 IP(但可被客戶端偽造)
  • 每經過一層代理,右側新增一個代理 IP
  • 可信策略:只信任已知代理 IP 陣列中最後一個非代理 IP

安全獲取真實 IP 最佳實踐

function getRealIp(array $trustedProxies = []): string {
    // 1. 直接連線環境
    if (empty($_SERVER['HTTP_X_FORWARDED_FOR'])) {
        return $_SERVER['REMOTE_ADDR'];
    }
    
    // 2. 解析 XFF 鏈
    $xff = $_SERVER['HTTP_X_FORWARDED_FOR'];
    $ips = array_map('trim', explode(',', $xff));
    
    // 3. 從右向左找第一個不在信任代理名單中的 IP
    $trusted = array_flip($trustedProxies); // O(1) 查找
    for ($i = count($ips) - 1; $i >= 0; $i--) {
        if (!isset($trusted[$ips[$i]])) {
            return $ips[$i];
        }
    }
    
    // 4. 全鏈路皆為信任代理(理論上不應發生)
    return $ips[0] ?? $_SERVER['REMOTE_ADDR'];
}

// 使用範例
$trustedProxies = [
    '10.0.0.1', '10.0.0.2',           // 內部負載均衡
    '192.168.1.100',                  // 反向代理
    // 雲端服務商 IP 範圍需查閱官方文檔
];
$realIp = getRealIp($trustedProxies);

常見雲端服務商信任代理 IP 範圍

  • AWS ALB/CloudFront:官方發布 IP 範圍 JSON,需定期同步
  • Cloudflare:CF-Connecting-IP 標頭更可靠,IP 範圍見 官網
  • Google Cloud LB:X-Forwarded-For 最後一個非 GCP IP
  • 阿里雲 SLB:X-Forwarded-For 格式標準,信任 100.64.0.0/10

偽造 IP 攻擊與防範

攻擊手法

// 攻擊者偽造標頭
$context = stream_context_create([
    'http' => [
        'header' => "X-Forwarded-For: 1.2.3.4\r\n" .
                    "Client-Ip: 5.6.7.8\r\n" .
                    "User-Agent: Mozilla/5.0...\r\n"
    ]
]);
file_get_contents('https://target.com/vote', false, $context);

防範策略

  1. 不盲目信任標頭:嚴格維護信任代理 IP 白名單
  2. 多層驗證:IP + Cookie + Session + 行為分析
  3. 速率限制:單 IP/分鐘請求上限、滑動視窗演算法
  4. 驗證碼:高風險操作觸發 reCAPTCHA / 圖形驗證碼
  5. 裝置指紋:Canvas 指紋、User-Agent 熵值、行為生物特徵
  6. 代理檢測:檢查 Via、X-Proxy-ID、開放代理掃描

完整防刷投票架構

class VoteService {
    private Redis $redis;
    private array $trustedProxies;
    
    public function vote(string $itemId, string $choice): bool {
        $ip = $this->getRealIp();
        $deviceId = $this->getDeviceFingerprint();
        
        // 1. 速率限制:IP 維度
        $ipKey = "vote:rate:ip:$ip";
        if ($this->redis->incr($ipKey) > 30) return false; // 30/分鐘
        $this->redis->expire($ipKey, 60);
        
        // 2. 速率限制:裝置維度
        $devKey = "vote:rate:dev:$deviceId";
        if ($this->redis->incr($devKey) > 10) return false; // 10/分鐘
        $this->redis->expire($devKey, 60);
        
        // 3. 防重複:業務鍵
        $voteKey = "vote:done:$itemId:$ip:$deviceId";
        if ($this->redis->exists($voteKey)) return false;
        
        // 4. 寫入投票(原子操作)
        $pipe = $this->redis->pipeline();
        $pipe->incr("vote:count:$itemId:$choice");
        $pipe->set($voteKey, 1, 'EX', 86400 * 30); // 30 天有效
        $pipe->exec();
        
        return true;
    }
    
    private function getDeviceFingerprint(): string {
        $ua = $_SERVER['HTTP_USER_AGENT'] ?? '';
        $accept = $_SERVER['HTTP_ACCEPT'] ?? '';
        $lang = $_SERVER['HTTP_ACCEPT_LANGUAGE'] ?? '';
        return substr(md5($ua . $accept . $lang), 0, 16);
    }
    
    private function getRealIp(): string {
        // ... 實作同上 ...
    }
}

關鍵原則總結

  1. REMOTE_ADDR 是底線:TCP 連線來源無法在應用層偽造
  2. XFF 需配合信任代理名單:盲目使用 = 安全漏洞
  3. 單一維度防禦必失敗:需 IP + 裝置 + 行為 + 驗證碼 多層疊加
  4. 業務鍵設計要精準:投票用 itemId + ip + device,而非單純 IP
  5. 記錄完整鏈路:日誌保存 XFF、UA、Referer、時間戳,事後可追溯

理解 IP 獲取的本質與局限,建立多層次防禦體系,才能在刷票、薅羊毛、惡意註冊等對抗中立於不敗之地。

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