在 PHP 開發中,資料加密是保護敏感資訊的關鍵手段。AES(Advanced Encryption Standard)作為目前最廣泛採用的對稱加密算法,因其安全性高、效能好,成為開發者的首選。本文將詳細介紹如何在 PHP 中正確實作 AES-256-CBC 加密與解密,並說明為何應棄用舊版 mcrypt 擴展,改用現代化的 openssl 函數庫。
早期 PHP 專案常使用 mcrypt 擴展實作 AES 加密。然而,mcrypt 自 PHP 7.1 起被棄用,並在 PHP 7.2 中完全移除。其主要問題包括:
因此,所有新專案與現有專案維護都應遷移至 openssl_encrypt() 與 openssl_decrypt()。
正確的 AES 實作需注意三個關鍵要素:
random_bytes(16)),並與密文一起儲存(通常前綴於密文前)。<?php
class AesEncryption
{
private const CIPHER = 'aes-256-cbc';
private const KEY_LENGTH = 32; // 256 bits
private const IV_LENGTH = 16; // 128 bits
private string $key;
public function __construct(string $secretKey)
{
// 使用 SHA-256 將任意長度的密鑰轉為 32 位元組
$this->key = hash('sha256', $secretKey, true);
}
/**
* 加密資料
* @param string $plaintext 明文
* @return string Base64 編碼的密文(含 IV 前綴)
*/
public function encrypt(string $plaintext): string
{
// 生成隨機 IV
$iv = random_bytes(self::IV_LENGTH);
// 加密
$ciphertext = openssl_encrypt(
$plaintext,
self::CIPHER,
$this->key,
OPENSSL_RAW_DATA,
$iv
);
if ($ciphertext === false) {
throw new \RuntimeException('加密失敗:' . openssl_error_string());
}
// 將 IV 前綴於密文,並 Base64 編碼便於儲存/傳輸
return base64_encode($iv . $ciphertext);
}
/**
* 解密資料
* @param string $encodedCiphertext Base64 編碼的密文(含 IV 前綴)
* @return string 明文
*/
public function decrypt(string $encodedCiphertext): string
{
$data = base64_decode($encodedCiphertext, true);
if ($data === false) {
throw new \InvalidArgumentException('無效的 Base64 編碼');
}
if (strlen($data) < self::IV_LENGTH) {
throw new \InvalidArgumentException('密文長度不足');
}
// 提取 IV 與實際密文
$iv = substr($data, 0, self::IV_LENGTH);
$ciphertext = substr($data, self::IV_LENGTH);
$plaintext = openssl_decrypt(
$ciphertext,
self::CIPHER,
$this->key,
OPENSSL_RAW_DATA,
$iv
);
if ($plaintext === false) {
throw new \RuntimeException('解密失敗:資料可能已損壞或金鑰錯誤');
}
return $plaintext;
}
}
// 使用範例
$crypto = new AesEncryption('MySecretKey123!@#');
$original = '敏感資料:信用卡號 4242-4242-4242-4242';
$encrypted = $crypto->encrypt($original);
echo "加密結果: {$encrypted}\n";
$decrypted = $crypto->decrypt($encrypted);
echo "解密結果: {$decrypted}\n";
// 驗證
assert($original === $decrypted, '加解密不一致');
?>
aes-256-gcm)或額外加上 HMAC 驗證(Encrypt-then-MAC)。若現有專案使用 mcrypt 並需相容舊密文,可撰寫相容層:先用 mcrypt 解密舊資料,再用 OpenSSL 重新加密儲存。漸進式遷移可降低風險。
採用 openssl 實作 AES-256-CBC 是目前 PHP 加密的標準做法。本文提供的類別封裝了隨機 IV 生成、金鑰派生與 Base64 編碼等最佳實踐,可直接用於生產環境。記住:加密只是資安拼圖的一塊,完整的防護還需包含傳輸層加密(TLS)、存取控制、審計日誌等多層次措施。