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

PHP Cookie 加密存儲方案:基於 OpenSSL 的 AES-256-ECB 實現與最佳實踐

     編輯:PHP 相關知識

為什麼要加密 Cookie?

  • 防止敏感信息(用戶 ID、權限標識、Token)在客戶端明文暴露。
  • 防範竄改:加密後任何修改均導致解密失敗(需配合簽名或認證加密)。
  • 滿足合規要求(如 GDPR、等保)對客戶端敏感數據保護規定。

注意:原文使用 mcrypt 擴展已棄用

原示例使用 MCRYPT_RIJNDAEL_256 (mcrypt),PHP 7.1 棄用,7.2 移除。**現代項目必須遷移至 OpenSSL (openssl_encrypt/decrypt) 或 Sodium (libsodium)**。本文提供 OpenSSL AES-256-CBC 版本(比 ECB 更安全,需 IV)。

現代化 Cookie 加密類

<?php
class SecureCookie {
    // 應用配置中應存儲 32 字節 Base64 編碼的密鑰
    private static $key;
    private static $cipher = 'AES-256-CBC'; // 推薦 CBC 模式
    private static $options = OPENSSL_RAW_DATA;

    public static function init($base64Key) {
        self::$key = base64_decode($base64Key);
        if (strlen(self::$key) !== 32) {
            throw new InvalidArgumentException('Key must be 32 bytes (256 bits) after base64 decode');
        }
    }

    /**
     * 加密並設置 Cookie
     * @param string $name   Cookie 名
     * @param mixed  $value  任意可序列化數據
     * @param int    $expire 過期時間戳
     * @param string $path   路徑
     * @param string $domain 域名
     * @param bool   $secure 僅 HTTPS
     * @param bool   $httponly 防 JS 訪問
     */
    public static function set($name, $value, $expire = 0, $path = '/', $domain = '', $secure = true, $httponly = true) {
        $plain = serialize($value);
        $ivLen = openssl_cipher_iv_length(self::$cipher);
        $iv = random_bytes($ivLen);
        $ciphertext = openssl_encrypt($plain, self::$cipher, self::$key, self::$options, $iv);
        if ($ciphertext === false) throw new RuntimeException('Encryption failed');
        // 存儲格式: iv(16字節) + ciphertext -> Base64
        $cookieValue = base64_encode($iv . $ciphertext);
        return setcookie($name, $cookieValue, $expire, $path, $domain, $secure, $httponly);
    }

    /**
     * 讀取並解密 Cookie
     * @return mixed|false 解密後的原始值,失敗返回 false
     */
    public static function get($name) {
        if (!isset($_COOKIE[$name])) return false;
        $data = base64_decode($_COOKIE[$name], true);
        if ($data === false) return false;
        $ivLen = openssl_cipher_iv_length(self::$cipher);
        if (strlen($data) < $ivLen) return false;
        $iv = substr($data, 0, $ivLen);
        $ciphertext = substr($data, $ivLen);
        $plain = openssl_decrypt($ciphertext, self::$cipher, self::$key, self::$options, $iv);
        if ($plain === false) return false;
        $value = @unserialize($plain);
        return ($value !== false || $plain === 'b:0;') ? $value : false; // 區分 false 與序列化失敗
    }

    public static function delete($name, $path = '/', $domain = '') {
        return setcookie($name, '', time() - 86400, $path, $domain);
    }
}

// --- 初始化 (僅需一次,如 bootstrap) ---
// 生成密鑰: base64_encode(random_bytes(32)) -> 存入配置文件
SecureCookie::init('YOUR_BASE64_ENCODED_32_BYTE_KEY_FROM_CONFIG');
?>

使用示例

<?php
// 設置加密 Cookie (存儲用戶信息)
$userData = ['uid' => 12345, 'role' => 'admin', 'login_at' => time()];
SecureCookie::set('user_session', $userData, time() + 3600*24*7); // 7天

// 讀取並自動解密
$user = SecureCookie::get('user_session');
if ($user) {
    echo "歡迎回來, UID: {$user['uid']}";
} else {
    echo "會話無效或已篡改";
}
?>

關鍵安全點

  1. 密鑰管理:密鑰**絕不**硬編碼在代碼中,應從環境變量、配置中心、密鑰管理服務 (KMS) 讀取。
  2. 認證加密 (AEAD):AES-CBC 僅提供機密性,**無完整性保護**。攻擊者可翻轉密文位導致解密後數據被竄改且不報錯。
    • **最佳方案**:使用 AES-256-GCM (PHP 7.1+) 或 sodium_crypto_aead_xchacha20poly1305_ietf_encrypt (libsodium),同時提供加密與認證標簽。
    • **折中方案**:CBC + HMAC-SHA256 (Encrypt-then-MAC),驗證 MAC 再解密。
  3. IV 唯一性:每次加密使用 random_bytes 生成隨機 IV,隨密文存儲(Base64 編碼前綴)。
  4. Cookie 屬性:生產環境強制 Secure=true (僅 HTTPS)、HttpOnly=true (防 XSS 竊取)、SameSite=Strict/Lax (防 CSRF)。
  5. 序列化風險:unserialize 可能觸發對象注入 (POP 鏈)。**建議改用 JSON**:json_encode/decode 替代 serialize/unserialize,僅存儲純數據結構。

遷移清單 (從 mcrypt 到 OpenSSL)

mcryptOpenSSL 替代備註
MCRYPT_RIJNDAEL_256AES-256 (Rijndael 256 位塊 = AES)AES 固定 128 位塊,mcrypt 支持 256 位塊,不兼容。需重新加密數據。
MCRYPT_MODE_ECB不推薦使用 ECBECB 無 IV,相同明文產生相同密文,嚴重洩露模式。必須改用 CBC/GCM。
mcrypt_create_ivrandom_bytes()CSPRNG,更安全。
mcrypt_encrypt/decryptopenssl_encrypt/decryptAPI 更簡潔,性能更好。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved