Discuz! 的 authcode() 採用自定義 XOR + Base64 + 動態密鑰機制,雖然曾廣泛使用,但不符合現代密碼學標準,存在已知弱點,新項目請勿使用。
核心流程:
=。認證加密 (AEAD) 同時保證機密性、完整性、防重放。
<?php
/**
* 現代加密工具類
*/
class Crypto {
const CIPHER = 'aes-256-gcm';
const KEY_LEN = 32; // 256 bit
const IV_LEN = 12; // 96 bit for GCM
const TAG_LEN = 16;
/** 從密碼派生金鑰 (PBKDF2) */
public static function deriveKey(string $password, string $salt): string {
return hash_pbkdf2('sha256', $password, $salt, 100_000, self::KEY_LEN, true);
}
/** 加密:返回 Base64(salt + iv + ciphertext + tag) */
public static function encrypt(string $data, string $password): string {
$salt = random_bytes(16);
$key = self::deriveKey($password, $salt);
$iv = random_bytes(self::IV_LEN);
$ciphertext = openssl_encrypt($data, self::CIPHER, $key, OPENSSL_RAW_DATA, $iv, $tag);
if ($ciphertext === false) throw new \Exception('加密失敗');
// 組合:salt(16) + iv(12) + ciphertext + tag(16)
return base64_encode($salt . $iv . $ciphertext . $tag);
}
/** 解密 */
public static function decrypt(string $payload, string $password): string {
$raw = base64_decode($payload, true);
if ($raw === false) throw new \Exception('Base64 解碼失敗');
$salt = substr($raw, 0, 16);
$iv = substr($raw, 16, 12);
$tag = substr($raw, -16);
$ciphertext = substr($raw, 28, -16);
$key = self::deriveKey($password, $salt);
$plaintext = openssl_decrypt($ciphertext, self::CIPHER, $key, OPENSSL_RAW_DATA, $iv, $tag);
if ($plaintext === false) throw new \Exception('解密失敗:數據被篡改或密碼錯誤');
return $plaintext;
}
}
// 使用示例
$pwd = 'MySuperSecretPassword2024!';
$token = Crypto::encrypt('敏感數據:用戶ID=12345', $pwd);
echo "加密: $token\n";
echo "解密: " . Crypto::decrypt($token, $pwd) . "\n";
| 場景 | 推薦方案 | 備註 |
|---|---|---|
| API Token、Session ID | JWT (RS256) / 隨機字符串 + 資料庫 | 無需對稱加密 |
| 用戶隱私字段落地加密 | AES-256-GCM | 金鑰管理用 Vault/KMS |
| 密碼存儲 | bcrypt / Argon2id | 單向哈希,絕不可逆 |
| 舊系統兼容 | authcode (僅解密) | 逐步遷移至新方案 |