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

PHP 用戶登入 Cookie 安全防護:加密儲存與 Token 驗證雙重機制

     編輯:PHP 相關知識

PHP 用戶登入 Cookie 安全防護:加密儲存與 Token 驗證雙重機制

Cookie 儲存在客戶端且可被竄改,直接儲存用戶識別資訊極易遭偽造登入。本文介紹兩種進階防護策略:對稱加密儲存 與 隨機 Token 綁定驗證,並提供可直接落地的 PHP 實作代碼。

風險分析

  • Cookie 可被用戶瀏覽、修改、複製至他機器
  • 若儲存 user_id=123 明文,攻擊者只需修改 ID 即可冒充任意用戶
  • 甚至可構造批量掃描工具嘗試不同 ID 獲取權限

方案一:對稱加密儲存(Discuz! 經典 authcode 實作)

核心原理:使用動態金鑰加密,相同明文每次產生不同密文,包含時間戳驗證有效期、完整性校驗碼。

<?php
/**
 * Discuz! 經典加密/解密函數
 * @param string $string 明文或密文
 * @param string $operation 'ENCODE' 加密 | 'DECODE' 解密
 * @param string $key 加密金鑰
 * @param int $expiry 有效期秒數(0=永久)
 * @return string 加密後字串 | 解密後明文 | 空字串(失敗)
 */
function authcode($string, $operation = 'DECODE', $key = '', $expiry = 0) {
    $ckey_length = 4; // 動態金鑰長度
    $key = md5($key ? $key : $GLOBALS['discuz_auth_key']);
    $keya = md5(substr($key, 0, 16));
    $keyb = md5(substr($key, 16, 16));
    $keyc = $ckey_length ? ($operation == 'DECODE' ? substr($string, 0, $ckey_length) : substr(md5(microtime()), -$ckey_length)) : '';
    $cryptkey = $keya . md5($keya . $keyc);
    $key_length = strlen($cryptkey);

    $string = $operation == 'DECODE'
        ? base64_decode(substr($string, $ckey_length))
        : sprintf('%010d', $expiry ? $expiry + time() : 0) . substr(md5($string . $keyb), 0, 16) . $string;
    $string_length = strlen($string);

    $result = '';
    $box = range(0, 255);
    $rndkey = [];
    for ($i = 0; $i <= 255; $i++) $rndkey[$i] = ord($cryptkey[$i % $key_length]);
    for ($j = $i = 0; $i < 256; $i++) {
        $j = ($j + $box[$i] + $rndkey[$i]) % 256;
        $tmp = $box[$i]; $box[$i] = $box[$j]; $box[$j] = $tmp;
    }
    for ($a = $j = $i = 0; $i < $string_length; $i++) {
        $a = ($a + 1) % 256;
        $j = ($j + $box[$a]) % 256;
        $tmp = $box[$a]; $box[$a] = $box[$j]; $box[$j] = $tmp;
        $result .= chr(ord($string[$i]) ^ ($box[($box[$a] + $box[$j]) % 256]));
    }

    if ($operation == 'DECODE') {
        if ((substr($result, 0, 10) == 0 || substr($result, 0, 10) - time() > 0) &&
            substr($result, 10, 16) == substr(md5(substr($result, 26) . $keyb), 0, 16)) {
            return substr($result, 26);
        }
        return '';
    } else {
        return $keyc . str_replace('=', '', base64_encode($result));
    }
}

// 使用範例:設定加密 Cookie
$user = array('uid'=>$uid, 'username'=>$username);
$user = base64_encode(serialize($user));
$user = authcode($user, 'ENCODE', 'your_secret_key', 0);
setcookie('user', $user, time() + 3600 * 24);

// 讀取驗證
$cookie = $_COOKIE['user'] ?? '';
$userData = authcode($cookie, 'DECODE', 'your_secret_key', 0);
if ($userData) {
    $user = @unserialize(base64_decode($userData));
    // $user['uid'], $user['username'] 可用
}
?>

方案二:隨機 Token 綁定驗證(伺服器端狀態)

核心原理:Cookie 僅儲存隨機 Token,真實用戶狀態儲存在伺服器端(資料庫/Redis/Memcache),Token 定期輪換。

<?php
// 登入成功時
$uid = 123; // 驗證通過的用戶 ID
$token = md5($uid . time() . mt_rand()); // 生成唯一 Token
$expire = time() + 3600 * 24; // 24 小時有效

// 1. 寫入資料庫 users 表
// UPDATE users SET login_token='$token', token_expire=$expire WHERE id=$uid

// 2. 設定 Cookie(僅儲存 Token)
setcookie('auth_token', $token, $expire, '/', '', false, true); // HttpOnly + Secure

// 3. Session 同步(可選,雙重保障)
$_SESSION['uid'] = $uid;
$_SESSION['token'] = $token;

// 驗證中介層(每次請求執行)
function checkAuth() {
    $token = $_COOKIE['auth_token'] ?? '';
    if (!$token) return false;

    // 從資料庫/快取查詢
    $row = query("SELECT uid FROM users WHERE login_token='$token' AND token_expire > " . time());
    if (!$row) return false;

    // 可選:延長有效期(滑動過期)
    // UPDATE users SET token_expire=" . (time() + 3600 * 24) . " WHERE uid={$row['uid']}

    return $row['uid'];
}
?>

兩種方案對比與選型建議

維度對稱加密 (authcode)Token 綁定驗證
伺服器端狀態無狀態有狀態(需儲存 Token)
防偽造能力強(需金鑰才能構造合法密文)極強(Token 無規律、伺服器驗證)
撤銷登入困難(需更換金鑰導致所有用戶失效)容易(刪除資料庫 Token 即可)
多裝置管理不支援支援(可儲存多 Token)
效能極高(純運算)需查詢儲存層(可用 Redis 優化)
適用場景中小型、無撤銷需求、追求極致效能中大型、需登出控制、多裝置、安全合規

通用安全加固清單

  1. HttpOnly:setcookie(..., true) 防止 JS 竊取
  2. Secure:HTTPS 環境下啟用 setcookie(..., '', true, true)
  3. SameSite:setcookie(..., ['samesite'=>'Lax']) 防 CSRF
  4. 金鑰管理:加密金鑰存放於環境變數或配置檔,勿硬編碼
  5. 最小權限:Cookie 僅儲存必要識別資訊,敏感資料留伺服器端

根據專案規模與安全等級選擇適合方案,Token 綁定驗證是現代 Web 應用的主流最佳實踐。

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