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

PHP Cookie 計數器實作:從基礎到防竄改進階版

     編輯:PHP 綜合知識

前言

Cookie 計數器是追蹤單一瀏覽器造訪次數的經典範例。雖原理簡單,但生產環境需考量:同站多頁面共享、防竄改、GDPR 合規、效能與安全性。本文從最小可行實作進階至生產級方案。

最小實作 (教學用)

<?php
// counter.php - 必須在任何輸出之前
if (!empty($_COOKIE['visit_count'])) {
    $count = (int)$_COOKIE['visit_count'] + 1;
} else {
    $count = 1;
}

// 15 小時過期 (54000 秒)
setcookie('visit_count', $count, [
    'expires' => time() + 54000,
    'path'    => '/',
    'secure'  => true,      // 僅 HTTPS
    'httponly' => true,     // 阻止 JS 存取
    'samesite' => 'Lax',    // CSRF 防護
]);
?>
<!DOCTYPE html>
<html>
<head><meta charset="utf-8"><title>造訪計數</title></head>
<body>
    <p>歡迎光臨!這是您第 <strong><?= $count ?></strong> 次造訪。</p>
</body>
</html>

關鍵安全屬性解析

屬性用途建議值
secure僅 HTTPS 傳輸true (正式環境)
httponly禁止 JavaScript 讀取 (防 XSS 竊取)true
samesite跨站請求攜帶策略Lax 或 Strict
path生效路徑/ (全站)
domain生效網域留空 (當前網域) 或 .example.com (含子網域)

進階版:簽名防竄改

使用者可修改 Cookie 值,若計數用於積點、抽獎等業務邏輯,需簽名驗證。

<?php
const COOKIE_NAME = 'visit_count';
const SECRET_KEY  = 'your-32-char-secret-key-here'; // 生產環境從環境變數讀取

function sign(int $value): string {
    return hash_hmac('sha256', (string)$value, SECRET_KEY);
}

function verify(string $cookie): ?int {
    [$value, $sig] = explode('.', $cookie, 2) + [null, null];
    if ($value === null || $sig === null) return null;
    if (!hash_equals(sign((int)$value), $sig)) return null;
    return (int)$value;
}

// 讀取並驗證
$count = 1;
if (isset($_COOKIE[COOKIE_NAME])) {
    $verified = verify($_COOKIE[COOKIE_NAME]);
    if ($verified !== null) {
        $count = $verified + 1;
    }
}

// 寫入簽名後的值
$signed = $count . '.' . sign($count);
setcookie(COOKIE_NAME, $signed, [
    'expires'  => time() + 86400 * 30, // 30 天
    'path'     => '/',
    'secure'   => true,
    'httponly' => true,
    'samesite' => 'Lax',
]);
?>
<p>第 <?= $count ?> 次造訪</p>

進階版:加密儲存敏感資料

若 Cookie 存放使用者 ID、權限等敏感資訊,建議使用 AEAD 加密 (PHP 7.1+ sodium 擴展)。

$key = sodium_hex2bin('your-64-hex-char-key'); // 32 bytes

function encryptCookie(array $data, string $key): string {
    $nonce = random_bytes(SODIUM_CRYPTO_AEAD_XCHACHA20POLY1305_IETF_NPUBBYTES);
    $plaintext = json_encode($data);
    $ciphertext = sodium_crypto_aead_xchacha20poly1305_ietf_encrypt(
        $plaintext, '', $nonce, $key
    );
    return base64_encode($nonce . $ciphertext);
}

function decryptCookie(string $cookie, string $key): ?array {
    $raw = base64_decode($cookie, true);
    if ($raw === false) return null;
    $nonceLen = SODIUM_CRYPTO_AEAD_XCHACHA20POLY1305_IETF_NPUBBYTES;
    $nonce = substr($raw, 0, $nonceLen);
    $ciphertext = substr($raw, $nonceLen);
    $plaintext = sodium_crypto_aead_xchacha20poly1305_ietf_decrypt(
        $ciphertext, '', $nonce, $key
    );
    return $plaintext ? json_decode($plaintext, true) : null;
}

GDPR / 隱私法合規提醒

  1. 告知與同意:首次造訪顯示 Cookie 横幅,說明用途並取得同意。
  2. expires 不宜過長:一般分析性 Cookie 建議 30 天內。
  3. 提供撤銷機制:隱私權頁面提供「清除我的 Cookie」按鈕 (呼叫 setcookie(..., ['expires' => time()-3600]))。
  4. 不在 Cookie 儲存個人識別資訊 (PII),改用 Server-side Session + Cookie 只存 Session ID。

常見問題排查

現象可能原因解決
計數永遠是 1Cookie 未寫入 / domain/path 不符檢查 Set-Cookie 標頭、瀏覽器開發者工具 Application 分頁
HTTPS 站點 Cookie 不送出未設 secure=true正式環境務必啟用
子網域無法共享domain 未設為 .example.com設定 domain => '.example.com'
計數異常暴增爬蟲/預渲染/多頁面重複計數排除 User-Agent、改用 Session 或加入 CSRF token 驗證

結語

Cookie 計數器看似簡單,實則牽涉 HTTP 協議、瀏覽器安全模型、隱私法規與密碼學。生產環境請務必啟用 Secure/HttpOnly/SameSite,涉及業務邏輯時加上簽名或加密,並遵循隱私法規設計同意與撤銷機制。

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