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

PHP API 介接 AES 加密實戰:CBC 模式、PKCS7 填充、Base64/URL 編碼、簽名驗證完整流程

     編輯:PHP 綜合知識

開放平台、金流、ERP 介接常要求請求/回應資料加密防止中間人竊取/竄改。AES-CBC + PKCS7 是業界標準配置。本文提供完整可用的 Crypt_AES 類、Client 端加密請求、Server 端解密驗證、簽名防重放完整流程。

核心參數協商(雙方約定)

參數說明範例
Key16/24/32 位元組(AES-128/192/256)1qa2ws4rf3edzxcv (16 bytes)
IV16 位元組初始向量dfg452ws (8 chars → 需擴展)
ModeCBC(需 IV)CBC
PaddingPKCS#7啟用
編碼加密後 Base64 → URL encode
簽名MD5(content + md5Key)

Crypt_AES 完整類(支援 mcrypt 兼容介面,PHP 7.1+ 建議改用 OpenSSL)

<?php
/**
 * AES 加解密工具類(教學用,生產建議用 openssl_encrypt)
 */
class Crypt_AES {
    private string $cipher = 'aes-128-cbc'; // OpenSSL cipher name
    private string $key;
    private string $iv;
    private bool $pkcs7 = true;

    public function __construct(string $key, string $iv, bool $pkcs7 = true) {
        $this->key = $key;
        $this->iv = $iv;
        $this->pkcs7 = $pkcs7;
    }

    public function encrypt(string $data): string {
        $data = $this->pkcs7 ? $this->pkcs7Pad($data) : $data;
        return openssl_encrypt($data, $this->cipher, $this->key, OPENSSL_RAW_DATA, $this->iv);
    }

    public function decrypt(string $data): string {
        $decrypted = openssl_decrypt($data, $this->cipher, $this->key, OPENSSL_RAW_DATA, $this->iv);
        return $this->pkcs7 ? $this->pkcs7Unpad($decrypted) : $decrypted;
    }

    private function pkcs7Pad(string $data): string {
        $block = 16;
        $pad = $block - (strlen($data) % $block);
        return $data . str_repeat(chr($pad), $pad);
    }

    private function pkcs7Unpad(string $data): string {
        $pad = ord($data[strlen($data) - 1]);
        if ($pad < 1 || $pad > 16) return $data; // 非法填充
        return substr($data, 0, -$pad);
    }

    // 十六進制字串轉二進位
    public static function hex2bin(string $hex): string {
        return pack('H*', $hex);
    }
    // 字串轉十六進制
    public static function strToHex(string $str): string {
        return bin2hex($str);
    }
}
?>

Client 端:加密請求發送

<?php
require 'Crypt_AES.php';

// 協商參數
$md5Key = 'ThisIsAMd5Key';
$aesKey = Crypt_AES::hex2bin(Crypt_AES::strToHex('1qa2ws4rf3edzxcv')); // 16 bytes
$aesIV  = Crypt_AES::hex2bin(Crypt_AES::strToHex('dfg452ws')); // 需 16 bytes,這裡示範擴展

$aes = new Crypt_AES($aesKey, $aesIV, true);

$data = [
    'name' => 'idoubi',
    'sex' => 'male',
    'age' => 23,
    'signature' => '白天我是一個程序員,晚上我就是一個有夢想的演員。',
];

// 1. JSON 序列化
$json = json_encode($data, JSON_UNESCAPED_UNICODE);
// 2. AES 加密
$encrypted = $aes->encrypt($json);
// 3. Base64 編碼
$b64 = base64_encode($encrypted);
// 4. URL 編碼
$content = urlencode($b64);
// 5. 簽名
$sign = md5($content . $md5Key);

// 6. 發送 POST
$params = "version=1.0&sign=$sign&content=$content";
$ch = curl_init('https://localhost/aesdemo/api.php');
curl_setopt_array($ch, [
    CURLOPT_POST => true,
    CURLOPT_POSTFIELDS => $params,
    CURLOPT_RETURNTRANSFER => true,
]);
$response = curl_exec($ch);
curl_close($ch);
var_dump(json_decode($response, true));
?>

Server 端:驗證簽名 → 解密 → 業務處理 → 加密回應

<?php
require 'Crypt_AES.php';

$md5Key = 'ThisIsAMd5Key';
$aesKey = Crypt_AES::hex2bin(Crypt_AES::strToHex('1qa2ws4rf3edzxcv'));
$aesIV  = Crypt_AES::hex2bin(Crypt_AES::strToHex('dfg452ws'));
$aes = new Crypt_AES($aesKey, $aesIV, true);

$content = $_POST['content'] ?? '';
$sign = $_POST['sign'] ?? '';

// 1. 驗證簽名(防竄改、防重放)
if (strcasecmp(md5($content . $md5Key), $sign) !== 0) {
    exit(json_encode(['code' => 401, 'msg' => '簽名驗證失敗']));
}

// 2. 解密
$b64 = urldecode($content);
$encrypted = base64_decode($b64);
$decrypted = $aes->decrypt($encrypted);
if ($decrypted === false) {
    exit(json_encode(['code' => 500, 'msg' => '解密失敗']));
}

$data = json_decode($decrypted, true);
// 業務邏輯...
$result = ['status' => 'ok', 'received' => $data];

// 3. 加密回應(同流程)
$respJson = json_encode($result, JSON_UNESCAPED_UNICODE);
$respEnc = $aes->encrypt($respJson);
$respB64 = base64_encode($respEnc);
$respContent = urlencode($respB64);
$respSign = md5($respContent . $md5Key);

echo json_encode([
    'version' => '1.0',
    'sign' => $respSign,
    'content' => $respContent
]);
?>

安全強化清單

  1. Key/IV 管理:Key 應從環境變數/密碼管理系統讀取,不可硬編碼。IV 每次請求隨機生成(隨密文傳輸),或雙方協商固定。
  2. 防重放攻擊:請求加入 timestamp + nonce,Server 驗證時間窗(±5min)+ Redis 去重 nonce。
  3. 演算法升級:新專案優先 AES-256-GCM(認證加密,無需額外簽名),PHP 用 openssl_encrypt(..., 'aes-256-gcm', ..., $tag)。
  4. HTTPS 強制:傳輸層加密是基礎,應用層加密是深度防禦。
  5. 錯誤訊息不洩露細節:統一回傳 code/msg,避免暴露堆疊、金鑰長度等資訊。

現代替代:OpenSSL AES-GCM(推薦)

<?php
function aesGcmEncrypt(string $data, string $key): string {
    $iv = random_bytes(12);
    $tag = '';
    $ct = openssl_encrypt($data, 'aes-256-gcm', $key, OPENSSL_RAW_DATA, $iv, $tag, '');
    return base64_encode($iv . $tag . $ct);
}
function aesGcmDecrypt(string $payload, string $key): ?string {
    $raw = base64_decode($payload);
    $iv = substr($raw, 0, 12);
    $tag = substr($raw, 12, 16);
    $ct = substr($raw, 28);
    return openssl_decrypt($ct, 'aes-256-gcm', $key, OPENSSL_RAW_DATA, $iv, $tag, '');
}
?>

結語

AES-CBC + PKCS7 + Base64 + MD5 簽名是舊版開放平台常見協議。理解其流程有助於維護舊系統,但新專案請直接用 AES-GCM 或 libsodium,減少自行實現的風險。

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