PHP 怎么客户端加密

wen PHP项目 1

本文目录导读:

PHP 怎么客户端加密

  1. 客户端加密方案(JavaScript)
  2. PHP 服务端解密
  3. 实际的常见场景
  4. 重要注意事项
  5. 完整示例:密码加密传输

在 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)) {
    // 签名有效
}

重要注意事项

⚠️ 安全警告

  1. 客户端加密不等于安全

    • 所有密钥和逻辑都暴露在浏览器中
    • 用户可以看到和修改代码
  2. 必须使用 HTTPS

    • 客户端加密是额外保护,不能替代 HTTPS
    • HTTPS 提供传输层加密
  3. 密钥管理

    • 永远不要在客户端密钥中写死密钥
    • 敏感密钥必须放在服务端
  4. 适合的场景

    • 短期敏感数据(如密码)的临时保护
    • 防止服务器日志记录明文数据
    • 数据完整性验证(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)

客户端加密主要用于增加一层防护,不能作为唯一的安全措施,核心安全还是依赖服务端验证。

抱歉,评论功能暂时关闭!