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

PHP 防止惡意重新整理與刷票完整解決方案:Token、Session、Cookie、Header 多層防禦

     編輯:PHP 綜合知識

惡意重新整理(F5 攻擊)、表單重複提交、投票刷票是 Web 應用常見痛點。本文系統整理 **Token 驗證、Session 限流、Cookie 標記、PRG 模式、JavaScript 輔助** 五大策略,並提供可直接落地的程式碼範例。

核心原則:冪等性與單次性

  • 冪等操作(查詢、GET)允許重複。
  • 非冪等操作(寫入、POST)必須保證「同一請求只處理一次」。

策略一:表單 Token(CSRF Token 同構)

<?php
session_start();

// 產生頁面時寫入 Token
$_SESSION['form_token'] = bin2hex(random_bytes(16));
?>
<?php // 處理頁面 if ($_SERVER['REQUEST_METHOD'] === 'POST') { if (!hash_equals($_SESSION['form_token'] ?? '', $_POST['token'] ?? '')) { die('Token 驗證失敗,請勿重複提交'); } // 成功後立即銷毀,防止重放 unset($_SESSION['form_token']); // 業務邏輯... header('Location: success.php'); // PRG 模式 exit; } ?>

策略二:Session 限流(時間窗口)

<?php
session_start();
$key = 'submit_limit_' . md5($_SERVER['REMOTE_ADDR'] . $_SERVER['REQUEST_URI']);
$limitSec = 30; // 30 秒內只允許一次

if (isset($_SESSION[$key]) && time() - $_SESSION[$key] < $limitSec) {
    http_response_code(429);
    die('操作太頻繁,請稍後再試');
}
$_SESSION[$key] = time();
// 繼續處理...
?>

策略三:Cookie 標記(跨 Session 持久)

<?php
$cookieName = 'vote_' . $pollId;
if (isset($_COOKIE[$cookieName])) {
    die('您已投過票');
}
// 驗證通過後
setcookie($cookieName, '1', [
    'expires' => time() + 86400 * 30, // 30 天
    'path' => '/',
    'httponly' => true,
    'samesite' => 'Lax',
]);
?>

⚠️ Cookie 可被清除/偽造,**不可作為唯一防線**,需搭配資料庫唯一鍵(用戶 ID + 投票 ID)。

策略四:PRG 模式

Post-Redirect-Get:處理 POST 後 **303 Redirect 到 GET 頁面**,瀏覽器重新整理只會重送 GET,不會重送 POST。

<?php
if ($_POST) {
    // 處理業務
    header('Location: ' . $_SERVER['PHP_SELF'], true, 303);
    exit;
}
// 顯示頁面(GET)
?>

策略五:JavaScript 前端攔截(輔助)

<script>
// 禁用提交按鈕防止連點
document.querySelector('form').addEventListener('submit', function(e) {
    const btn = this.querySelector('button[type=submit]');
    if (btn.disabled) e.preventDefault();
    btn.disabled = true;
    btn.textContent = '處理中...';
});

// 歷史導向阻擋(效果有限)
history.pushState(null, '', location.href);
window.onpopstate = () => history.go(1);
</script>

綜合防禦架構(生產級)

層級技術防禦目標可繞過性
資料庫唯一索引重複資料入庫不可繞過
應用層Token + PRG表單重複提交低
應用層Session/Redis 限流高頻刷單/刷票中(換 IP/瀏覽器)
前端JS 禁用按鈕誤觸/連點高(可停用 JS)
網關Nginx limit_reqCC 攻擊/洪水請求低

投票系統專用:資料庫層去重

<?php
// 唯一索引:UNIQUE KEY `uniq_vote` (`poll_id`, `user_id`)
// 或 IP 限制:UNIQUE KEY `uniq_vote_ip` (`poll_id`, `ip`)

try {
    $pdo->prepare("INSERT INTO votes (poll_id, user_id, option_id) VALUES (?,?,?)")
        ->execute([$pollId, $userId, $optionId]);
    echo '投票成功';
} catch (PDOException $e) {
    if ($e->getCode() === '23000') { // 23000 = integrity constraint violation
        echo '您已投過票';
    } else {
        throw $e;
    }
}
?>

總結

**沒有單一銀彈**。資料庫唯一鍵是最後防線,Token+PRG 解決 90% 重複提交,Redis 限流應對高併發,Nginx 限流擋住惡意流量。分層防禦,才能安心睡覺。

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