本文目录导读:

在 PHP 开发中,客户端加密通常指的是浏览器端(JavaScript)加密,因为 PHP 本身是服务端语言,不能直接在客户端运行,PHP 可以配合 JavaScript 实现完整的加密方案。
客户端加密方案(JavaScript)
Web Crypto API(推荐)
现代浏览器内置的加密标准,无需额外库。
// 生成密钥
const key = await crypto.subtle.generateKey(
{ name: 'AES-GCM', length: 256 },
true,
['encrypt', 'decrypt']
);
// 加密数据
async function encryptData(data, key) {
const encoder = new TextEncoder();
const dataBuffer = encoder.encode(data);
const iv = crypto.getRandomValues(new Uint8Array(12));
const encrypted = await crypto.subtle.encrypt(
{ name: 'AES-GCM', iv: iv },
key,
dataBuffer
);
return {
encrypted: new Uint8Array(encrypted),
iv: iv
};
}
// 使用
const result = await encryptData('要加密的数据', key);
CryptoJS(第三方库)
更简单,兼容老浏览器。
// 引入 CryptoJS
<script src="https://cdnjs.cloudflare.com/ajax/libs/crypto-js/4.1.1/crypto-js.min.js"></script>
// AES 加密
const key = CryptoJS.enc.Utf8.parse('your-secret-key-32bytes');
const iv = CryptoJS.lib.WordArray.random(16);
function encryptData(data) {
const encrypted = CryptoJS.AES.encrypt(data, key, {
iv: iv,
mode: CryptoJS.mode.CBC,
padding: CryptoJS.pad.Pkcs7
});
return {
ciphertext: encrypted.toString(),
iv: CryptoJS.enc.Hex.stringify(iv)
};
}
PHP 服务端解密
<?php
// 使用 OpenSSL 解密(对应 Web Crypto API)
function decryptClientData($encryptedBase64, $ivBase64, $key) {
$encrypted = base64_decode($encryptedBase64);
$iv = base64_decode($ivBase64);
$decrypted = openssl_decrypt(
$encrypted,
'AES-256-GCM',
$key,
OPENSSL_RAW_DATA,
$iv,
$tag // 如果需要认证标签
);
return $decrypted;
}
// 对应 CryptoJS 的 AES-CBC 解密
function decryptCryptoJSData($ciphertext, $ivHex, $key) {
$iv = hex2bin($ivHex);
$encrypted = base64_decode($ciphertext);
return openssl_decrypt(
$encrypted,
'AES-256-CBC',
$key,
OPENSSL_RAW_DATA,
$iv
);
}
实际的常见场景
密码传输加密(HTTPS 之外的额外保护)
// 前端
// 获取 RSA 公钥
const publicKey = await fetch('/api/public-key').then(r => r.json());
async function encryptPassword(password) {
const keyData = await importPublicKey(publicKey);
const encrypted = await crypto.subtle.encrypt(
{
name: 'RSA-OAEP',
algorithm: { name: 'RSA-OAEP', hash: 'SHA-256' }
},
keyData,
new TextEncoder().encode(password)
);
return btoa(String.fromCharCode(...new Uint8Array(encrypted)));
}
// PHP 服务端
$encryptedPassword = $_POST['encrypted_password'];
$privateKey = openssl_pkey_get_private(file_get_contents('private.pem'));
openssl_private_decrypt(
base64_decode($encryptedPassword),
$decrypted,
$privateKey,
OPENSSL_PKCS1_OAEP_PADDING
);
防篡改请求(HMAC 签名)
// 前端生成签名
async function generateSignature(data, secretKey) {
const encoder = new TextEncoder();
const dataBuffer = encoder.encode(JSON.stringify(data));
const key = await crypto.subtle.importKey(
'raw',
encoder.encode(secretKey),
{ name: 'HMAC', hash: 'SHA-256' },
false,
['sign']
);
const signature = await crypto.subtle.sign('HMAC', key, dataBuffer);
return btoa(String.fromCharCode(...new Uint8Array(signature)));
}
// 发送请求时携带签名
fetch('/api/secure', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-Signature': signature
},
body: JSON.stringify(data)
});
// PHP 验证签名
$signature = $_SERVER['HTTP_X_SIGNATURE'];
$data = file_get_contents('php://input');
$secretKey = 'your-secret-key';
$expectedSignature = base64_encode(
hash_hmac('sha256', $data, $secretKey, true)
);
if (hash_equals($expectedSignature, $signature)) {
// 签名有效
}
重要注意事项
⚠️ 安全警告:
-
客户端加密不等于安全
- 所有密钥和逻辑都暴露在浏览器中
- 用户可以看到和修改代码
-
必须使用 HTTPS
- 客户端加密是额外保护,不能替代 HTTPS
- HTTPS 提供传输层加密
-
密钥管理
- 永远不要在客户端密钥中写死密钥
- 敏感密钥必须放在服务端
-
适合的场景
- 短期敏感数据(如密码)的临时保护
- 防止服务器日志记录明文数据
- 数据完整性验证(HMAC)
完整示例:密码加密传输
// 前端 (encrypt.js)
async function submitWithEncryption() {
const password = document.getElementById('password').value;
// 获取服务器公钥
const response = await fetch('/api/get-rsa-key');
const { publicKey } = await response.json();
// 导入公钥
const key = await crypto.subtle.importKey(
'spki',
base64ToArrayBuffer(publicKey),
{
name: 'RSA-OAEP',
hash: 'SHA-256'
},
false,
['encrypt']
);
// 加密密码
const encrypted = await crypto.subtle.encrypt(
{ name: 'RSA-OAEP' },
key,
new TextEncoder().encode(password)
);
// 提交加密数据
const formData = new FormData();
formData.append('encrypted_password', arrayBufferToBase64(encrypted));
fetch('/api/login', {
method: 'POST',
body: formData
});
}
// PHP 后端 (login.php)
<?php
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$encryptedPassword = base64_decode($_POST['encrypted_password']);
// 私钥解密
$privateKey = openssl_pkey_get_private(file_get_contents('rsa_private.pem'));
openssl_private_decrypt(
$encryptedPassword,
$decryptedPassword,
$privateKey,
OPENSSL_PKCS1_OAEP_PADDING
);
// 验证密码
if (password_verify($decryptedPassword, $user['password_hash'])) {
// 登录成功
}
}
建议组合使用:
- HTTPS(传输层加密)
- 客户端加密(敏感数据额外保护)
- 服务端验证(如 HMAC 签名)
- 安全令牌(防 CSRF)
客户端加密主要用于增加一层防护,不能作为唯一的安全措施,核心安全还是依赖服务端验证。