刷票行為無法從根本杜絕,但可通過「提高攻擊成本 + 降低攻擊收益 + 實時風控攔截」構建多層防禦體系。本文基於 PHP 環境,系統梳理 10 大防刷技術手段,從客戶端偽造識別到服務端風控模型,附代碼示例與架構建議。
| 攻擊手段 | 特徵 | 防禦重點 |
|---|---|---|
| CURL 偽造 Header/IP/UA/Referer | 低成本、高併發、參數可控 | 設備指紋、行為分析、驗證碼 |
| 代理 IP 池輪換 | IP 多樣化、地理分布廣 | IP 信譽庫、頻率限制、設備綁定 |
| 自動化腳本/瀏覽器自動化 | 模擬真人操作軌跡 | JS 挑戰、滑塊驗證碼、行為生物識別 |
| 內部刷單/水軍 | 真實設備、真實網絡 | 業務風控模型、扣量邏輯、審計追溯 |
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, "https://target.com/vote.php");
curl_setopt($ch, CURLOPT_HTTPHEADER, [
'X-FORWARDED-FOR: 8.8.8.8',
'CLIENT-IP: 8.8.8.8'
]);
curl_setopt($ch, CURLOPT_REFERER, "https://target.com/");
curl_setopt($ch, CURLOPT_USERAGENT, "Mozilla/5.0 ...");
curl_setopt($ch, CURLOPT_HEADER, 1);
$out = curl_exec($ch);
對策:
• 檢查 $_SERVER['HTTP_X_FORWARDED_FOR']、HTTP_CLIENT_IP 一致性
• 校驗 User-Agent 特徵庫(無 HeadlessChrome、PhantomJS 特徵)
• 關鍵接口要求 Referer 同源
• 強制 HTTPS,防範中間人篡改 Header
// 僅允許 08:00-23:00 投票
$hour = (int)date('H');
if ($hour < 8 || $hour > 23) exit('非投票時間');
配合業務高峰期動態調整,減少夜間機器流量干擾。
// Redis 計數器 + 過期時間
$key = "vote_freq:{$userId}:{$itemId}";
$cnt = $redis->incr($key);
if ($cnt == 1) $redis->expire($key, 3600); // 1小時窗口
if ($cnt > 5) exit('操作太頻繁,請稍後再試');
分層限流:用戶級、IP 級、設備級、全局級,多維度疊加。
+1(樂觀 UI),實際計數異步更新。{success: true, msg: '感謝投票'},不直接返回最新票數。// 後台風控腳本:檢測異常增長
$growth = $currentVotes - $lastCheckVotes;
if ($growth > $threshold && $isSuspicious($itemId)) {
// 扣量:每 10 票算 1 票
$realVotes = floor($currentVotes / 10);
$db->update("items SET display_votes = $realVotes WHERE id = $itemId");
logAlert("扣量觸發: item=$itemId, raw=$currentVotes, display=$realVotes");
}
原則:不封禁、不提示、只降權。攻擊者以為成功實則無效,成本極高。
// 投票後寫入 HttpOnly Cookie
setcookie('voted_' . $itemId, '1', time()+86400, '/', '', true, true);
// 下次請求快速攔截
if (isset($_COOKIE['voted_' . $itemId])) exit('已投過票');
繞過成本極低(清 Cookie),僅作輔助,不可作核心依賴。
// 生成帶時間戳、隨機鹽的加密 token
function encryptOptionId($itemId, $userId) {
$salt = random_bytes(16);
$payload = json_encode(['item'=>$itemId, 'uid'=>$userId, 'ts'=>time(), 'salt'=>bin2hex($salt)]);
return base64_encode(openssl_encrypt($payload, 'AES-256-CBC', $secretKey, OPENSSL_RAW_DATA, $salt));
}
// 服務端解密驗證
function decryptOptionId($token) {
$data = json_decode(openssl_decrypt(base64_decode($token), 'AES-256-CBC', $secretKey, OPENSSL_RAW_DATA, $salt), true);
if (!$data || time() - $data['ts'] > 300) return false; // 5分鐘有效期
return $data['item'];
}
防止直接遍歷 item_id=1,2,3... 刷票,強制攻擊方破解加密算法或獲取有效 Token。
# nginx.conf
limit_conn_zone $binary_remote_addr zone=perip:10m;
limit_req_zone $binary_remote_addr zone=perip:10m rate=10r/s;
server {
location /vote/ {
limit_conn perip 20;
limit_req zone=perip burst=5 nodelay;
limit_rate 100k; # 限速
proxy_pass https://php_backend;
}
}
ngx_http_limit_conn_module:限制併發連接數ngx_http_limit_req_module:漏桶限制請求速率nginx_limit_speed_module:限制響應傳輸速度注意:Nginx 層只能按 IP 限流,無法識別用戶/設備,建議作第一道防線。
#!/bin/bash
# 1. 最近模塊:60秒內超過10個新連接 DROP
/sbin/iptables -A INPUT -p tcp --dport 80 --syn -m recent --name webpool --rcheck --seconds 60 --hitcount 10 -j DROP
/sbin/iptables -A INPUT -p tcp --dport 80 --syn -m recent --name webpool --set -j ACCEPT
# 2. connlimit:單 IP 併發連接數超過 10 REJECT
/sbin/iptables -t filter -A INPUT -p tcp --dport 80 --tcp-flags FIN,SYN,RST,ACK SYN -m connlimit --connlimit-above 10 --connlimit-mask 32 -j REJECT
# 3. 動態封禁腳本(crontab 每分鐘執行)
while true; do
for IP in $(netstat -an | grep ':80 ' | grep ESTAB | awk '{print $5}' | cut -d: -f1 | sort | uniq -c | awk '{if($1>30 && $2!="127.0.0.1") print $2}'); do
/sbin/iptables -L -n | grep -q $IP || /sbin/iptables -A INPUT -p tcp --dport 80 -s $IP -j DROP
echo "/sbin/iptables -A INPUT -p tcp -s $IP -j DROP" >> /tmp/iptables_conf.log
done
sleep 1
done
系統級防禦成本低、效果立竿見影,但屬於「核彈級」手段,誤封風險高,建議配合白名單、告警機制。
┌─────────────────────────────────────┐
│ 客戶端:驗證碼、JS 挑戰、設備指紋 │ ← 提高攻擊成本
├─────────────────────────────────────┤
│ 接入層:Nginx 限流、WAF、IP 信譽 │ ← 擋住 80% 低級流量
├─────────────────────────────────────┤
│ 業務層:頻率控制、加密 Token、扣量 │ ← 核心邏輯風控
├─────────────────────────────────────┤
│ 數據層:異步展示、審計日誌、實時監控 │ ← 事後追溯與決策
├─────────────────────────────────────┤
│ 系統層:iptables、系統資源隔離 │ ← 兜底防禦
└─────────────────────────────────────┘
防刷票是攻防對抗的長期博弈,沒有銀彈,只有持續迭代的體系化工程。