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

Discuz! authcode 加密解密函式深度解析與安全性評估

     編輯:PHP 相關知識

函式簽名與參數

function authcode(string $string, string $operation = 'DECODE', string $key = '', int $expiry = 0): string
  • $string:明文(加密時)或密文(解密時)。
  • $operation:ENCODE 加密、DECODE 解密。
  • $key:自訂金鑰,留空則用 $GLOBALS['discuz_auth_key'](Discuz 設定檔常數)。
  • $expiry:有效期秒數(加密時),0 表永久。解密時會驗證是否過期。

核心演算法流程

  1. 金鑰衍生:$key = md5($key ?: $GLOBALS['discuz_auth_key']) → 32 字元十六進位。
  2. 三組子金鑰:
    • $keya = md5(substr($key, 0, 16)):參與加解密運算(16 字元)。
    • $keyb = md5(substr($key, 16, 16)):資料完整性驗證(16 字元)。
    • $keyc:動態金鑰(4 字元預設),加密時取 md5(microtime()) 末 4 碼,解密時從密文前 4 碼取出。**這是相同明文每次產生不同密文的關鍵。**
  3. 最終加密金鑰:$cryptkey = $keya . md5($keya . $keyc)(長度 32+32=64 字元)。
  4. 明文預處理(加密):
    $plain = sprintf('%010d', $expiry ? $expiry + time() : 0)  // 10 位數時間戳(過期檢查)
             . substr(md5($string . $keyb), 0, 16)                       // 16 字元完整性檢查碼
             . $string;                                                  // 原始明文
    
  5. RC4 類流式加密:
    • 建立 256 字節 S-box ($box) 並用 $cryptkey 打亂(KSA 階段)。
    • 逐字元異或 (XOR) 加密:$result .= chr(ord($plain[$i]) ^ $box[($box[$a] + $box[$j]) % 256])(PRGA 階段)。
  6. 輸出編碼:$keyc . str_replace('=', '', base64_encode($result))。前綴動態金鑰、Base64 編碼移除填充 =。
  7. 解密驗證:
    1. 取前 4 碼 $keyc,重建 $cryptkey。
    2. Base64 解碼、RC4 解密(對稱運算)。
    3. 驗證時間戳:substr($decrypted, 0, 10) == 0 || ... - time() > 0(未過期)。
    4. 驗證完整性碼:substr($decrypted, 10, 16) == substr(md5(substr($decrypted, 26) . $keyb), 0, 16)。
    5. 通過則回傳 substr($decrypted, 26)(原始明文),否則回傳空字串。

安全性評估(現代視角)

項目評估風險
演算法自訂 RC4 變體高:RC4 已知偏差攻擊、密鑰排程弱點,不建議新系統使用
金鑰長度實際加密金鑰 256 bits (md5x2)中:理論足夠,但 RC4 弱化有效強度
動態 IV$keyc 4 字元 (32 bits)高:空間極小 (16^4=65536),極易重複,導致密文重複攻擊
完整性保護MD5 截斷 16 字元 (64 bits)中:MD5 碰撞風險,截斷進一步降低強度
時間戳防重放10 位數秒級低:秒級精度無法防禦同秒重放
Base64 編碼標準無風險

已知攻擊向量

  • 密文重複攻擊:$keyc 只有 4 字元,大量加密極易產生相同 $keyc,導致相同明文產生相同密文核心部分,洩露資訊。
  • RC4 偏差利用:前 256 位元組輸出偏差可被統計分析還原明文。
  • 金鑰洩露擴散:單一 $GLOBALS['discuz_auth_key'] 保護全站所有加密資料,一旦洩露全盤皆駭。
  • 無認證加密 (AEAD):缺乏現代認證加密機制(如 AES-GCM、ChaCha20-Poly1305),無法同時保證機密性與完整性防竄改。

現代替代方案建議

// 使用 PHP 內建 sodium 擴展(PHP 7.2+)或 openssl
function modernEncrypt(string $data, string $key): string {
    // $key 必須為 32 位元組 (256 bits),可用 hash('sha256', $masterKey, true) 衍生
    $nonce = random_bytes(SODIUM_CRYPTO_SECRETBOX_NONCEBYTES); // 24 bytes
    $cipher = sodium_crypto_secretbox($data, $nonce, $key);
    return base64_encode($nonce . $cipher);
}

function modernDecrypt(string $payload, string $key): string|false {
    $raw = base64_decode($payload, true);
    if ($raw === false) return false;
    $nonce = substr($raw, 0, SODIUM_CRYPTO_SECRETBOX_NONCEBYTES);
    $cipher = substr($raw, SODIUM_CRYPTO_SECRETBOX_NONCEBYTES);
    return sodium_crypto_secretbox_open($cipher, $nonce, $key);
}
  • 演算法:XChaCha20-Poly1305 (libsodium) 或 AES-256-GCM (OpenSSL),皆為經過嚴密審計的 AEAD 模式。
  • Nonce/IV:24 位元組隨機產生,空間極大 (2^192),實際不會重複。
  • 完整性:內建認證標籤,任何竄改解密即失敗。
  • 金鑰管理:建議用 HKDF 從主金鑰衍生用途專用金鑰,定期輪換。

結語

Discuz authcode 是早期 PHP 社群廣泛使用的經典加密函式,設計巧妙(動態 IV、時間戳、完整性碼、RC4 流式),但在現代密碼學標準下**不再安全**,存在 IV 空間過小、RC4 弱點、MD5 碰撞、缺乏 AEAD 等嚴重缺陷。**新專案請務必使用 libsodium (sodium_*) 或 OpenSSL AES-GC/ChaCha20-Poly1305**,並妥善管理金鑰生命週期。維護舊系統時,若無法立即替換,至少增加傳輸層 TLS、限制加密資料敏感度、監控異常解密失敗。

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