PHP API 接口数据加密传输实战指南
在PHP API开发中,明文传输数据极易被中间人窃听、篡改,尤其是涉及用户隐私、交易凭证等敏感场景时,数据加密是必选项。本文介绍一种兼顾安全性与性能的「RSA+AES混合加密+签名校验」方案,可直接落地到生产环境。
核心方案设计
该方案结合非对称加密与对称加密的优势:RSA用于安全传输随机生成的AES密钥,解决对称加密密钥分发难题;AES用于加密实际业务数据,效率高适合大数据量传输。额外增加签名校验机制,可有效避免数据被篡改。
具体实现步骤
1. 生成RSA密钥对
服务端生成公私钥对,公钥分发给所有调用方,私钥严格保存在服务端,权限设为仅当前用户可读:
<?php
$config = [
"digest_alg" => "sha256",
"private_key_bits" => 2048,
"private_key_type" => OPENSSL_KEYTYPE_RSA,
];
$res = openssl_pkey_new($config);
openssl_pkey_export($res, $privateKey);
$publicKey = openssl_pkey_get_details($res)["key"];
file_put_contents(__DIR__ . '/private.key', $privateKey);
chmod(__DIR__ . '/private.key', 0600);
file_put_contents(__DIR__ . '/public.key', $publicKey);
?>
2. 核心工具函数实现
<?php
// RSA私钥解密
function rsaDecrypt(string $encryptedData, string $privateKeyPath): string|false {
$privateKey = file_get_contents($privateKeyPath);
$decrypted = '';
if (openssl_private_decrypt(base64_decode($encryptedData), $decrypted, $privateKey, OPENSSL_PKCS1_OAEP_PADDING)) {
return $decrypted;
}
return false;
}
// RSA公钥加密
function rsaEncrypt(string $data, string $publicKeyPath): string|false {
$publicKey = file_get_contents($publicKeyPath);
$encrypted = '';
if (openssl_public_encrypt($data, $encrypted, $publicKey, OPENSSL_PKCS1_OAEP_PADDING)) {
return base64_encode($encrypted);
}
return false;
}
// AES加密(返回密文+IV,Base64编码)
function aesEncrypt(string $data, string $key): string|false {
$ivLen = openssl_cipher_iv_length('AES-256-CBC');
$iv = openssl_random_pseudo_bytes($ivLen);
$encrypted = openssl_encrypt($data, 'AES-256-CBC', $key, 0, $iv);
if (!$encrypted) return false;
return base64_encode($encrypted . '::' . $iv);
}
// AES解密
function aesDecrypt(string $encryptedData, string $key): string|false {
$raw = base64_decode($encryptedData);
$parts = explode('::', $raw);
if (count($parts) !== 2) return false;
[$encrypted, $iv] = $parts;
return openssl_decrypt($encrypted, 'AES-256-CBC', $key, 0, $iv);
}
// 生成签名(参数字典序排序后拼接密钥哈希)
function generateSign(array $data, string $secretKey): string {
ksort($data);
$str = http_build_query($data) . $secretKey;
return hash('sha256', $str);
}
?>
3. 服务端接口处理逻辑
接口接收客户端传递的加密参数,解密后校验签名再处理业务,返回加密响应:
<?php
require_once 'crypto.php';
$encryptedKey = $_POST['encrypted_key'] ?? '';
$encryptedData = $_POST['data'] ?? '';
$sign = $_POST['sign'] ?? '';
$apiSecret = 'your_api_secret';
// 解密AES密钥
$aesKey = rsaDecrypt($encryptedKey, __DIR__ . '/private.key');
if (!$aesKey) die(json_encode(['code' => 400, 'msg' => '密钥解密失败']));
// 解密业务数据
$businessData = aesDecrypt($encryptedData, $aesKey);
if (!$businessData) die(json_encode(['code' => 400, 'msg' => '数据解密失败']));
$dataArr = json_decode($businessData, true);
// 校验签名
$calcSign = generateSign($dataArr, $apiSecret);
if (!hash_equals($calcSign, $sign)) die(json_encode(['code' => 400, 'msg' => '签名校验失败']));
// 处理业务逻辑
// ...
// 返回加密响应
$responseData = ['code' => 200, 'msg' => 'success'];
$responseAesKey = openssl_random_pseudo_bytes(32);
echo json_encode([
'encrypted_key' => rsaEncrypt($responseAesKey, __DIR__ . '/public.key'),
'data' => aesEncrypt(json_encode($responseData), $responseAesKey)
]);
?>
关键注意事项:
- RSA私钥禁止提交到代码仓库,建议通过环境变量加载,权限严格控制在服务端;
- AES密钥需每次请求随机生成,禁止硬编码固定密钥;
- 加密是HTTPS的二次防护,建议始终启用HTTPS避免中间人攻击;
- 可增加timestamp参数防重放,服务端校验请求时间差在5分钟内才有效。
该方案兼顾安全性与性能,可覆盖绝大多数PHP API加密传输场景,开发者可根据需求替换为SM2/SM4等国产加密算法。
(全文约820字)