本文目录导读:

这是一个非常经典的混合加密方案(Hybrid Encryption),在单次接口通信中,RSA(非对称加密)用于安全传输AES的密钥,AES(对称加密)用于高效加密实际数据。
下面我会提供一个标准的、高安全性的实现流程,包含 Node.js 和浏览器端的示例代码。
核心逻辑
- 客户端:生成一个随机的 AES 密钥。
- 客户端:用这个 AES 密钥加密请求体的
JSON数据(得到encryptedData)。 - 客户端:用服务端的 RSA 公钥 加密这个 AES 密钥(得到
encryptedKey)。 - 客户端:将
encryptedKey和encryptedData一起发送给服务端。 - 服务端:用自己的 RSA 私钥解密
encryptedKey,得到 AES 密钥。 - 服务端:用这个 AES 密钥解密
encryptedData,得到原始请求数据。
准备 RSA 密钥对 (服务端)
服务端需要生成 2048 位或更长的 RSA 密钥对。
# 生成私钥 openssl genpkey -algorithm RSA -out private_key.pem -pkeyopt rsa_keygen_bits:2048 # 从私钥导出公钥 openssl rsa -pubout -in private_key.pem -out public_key.pem
private_key.pem: 放在服务端,绝对保密。public_key.pem: 分发给客户端(前端/移动端)。
客户端加密 (以浏览器/Node.js为例)
我们使用 Web Crypto API (浏览器) 或 Node.js crypto 模块。
依赖库安装 (Node.js 环境)
npm install node-forge # 或者使用内置 crypto 模块,但 forje 在浏览器端更容易移植
客户端加密代码 (JavaScript)
// 假设你已经从服务器获取了 RSA 公钥字符串
const rsaPublicKeyPem = `-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAr...
-----END PUBLIC KEY-----`;
// 1. 生成 AES 密钥 (随机 256位)
function generateAESKey() {
// 使用 Web Crypto API (浏览器环境)
if (window.crypto && window.crypto.subtle) {
return crypto.subtle.generateKey({
name: "AES-CBC",
length: 256
}, true, ["encrypt", "decrypt"]);
}
// 回退到 Node.js (这里不演示,因为浏览器更常见)
throw new Error("Crypto API not supported");
}
// 2. 使用 AES 加密数据
async function encryptDataWithAES(aesKey, plaintext) {
const encoder = new TextEncoder();
const data = encoder.encode(JSON.stringify(plaintext)); // 先转JSON
const iv = crypto.getRandomValues(new Uint8Array(16)); // 初始化向量,非常重要
const encrypted = await crypto.subtle.encrypt({
name: "AES-CBC",
iv: iv
}, aesKey, data);
// 返回 IV 和密文的 base64 拼接 (或者分开传)
return {
iv: arrayBufferToBase64(iv),
data: arrayBufferToBase64(encrypted)
};
}
// 3. 使用 RSA 公钥加密 AES 密钥
async function encryptAESKeyWithRSA(rsaPublicKeyPem, aesKey) {
// 1. 导入公钥
const publicKey = await importRSAPublicKey(rsaPublicKeyPem);
// 2. 导出 AES 密钥的原始字节
const rawAesKey = await crypto.subtle.exportKey("raw", aesKey);
// 3. 使用 RSA-OAEP 加密 (推荐)
const encryptedKey = await crypto.subtle.encrypt({
name: "RSA-OAEP"
}, publicKey, rawAesKey);
return arrayBufferToBase64(encryptedKey);
}
// 辅助函数: 导入 RSA 公钥
async function importRSAPublicKey(pem) {
const pemHeader = "-----BEGIN PUBLIC KEY-----";
const pemFooter = "-----END PUBLIC KEY-----";
const pemContents = pem.substring(pemHeader.length, pem.length - pemFooter.length);
const binaryDer = base64ToArrayBuffer(pemContents);
return await crypto.subtle.importKey(
"spki",
binaryDer,
{
name: "RSA-OAEP",
hash: "SHA-256"
},
false,
["encrypt"]
);
}
// 辅助函数: ArrayBuffer 转 Base64
function arrayBufferToBase64(buffer) {
let binary = '';
const bytes = new Uint8Array(buffer);
for (let i = 0; i < bytes.byteLength; i++) {
binary += String.fromCharCode(bytes[i]);
}
return btoa(binary);
}
function base64ToArrayBuffer(base64) {
const binaryString = atob(base64);
const bytes = new Uint8Array(binaryString.length);
for (let i = 0; i < binaryString.length; i++) {
bytes[i] = binaryString.charCodeAt(i);
}
return bytes.buffer;
}
// 主流程: 加密请求
async function encryptRequest(payload) {
const aesKey = await generateAESKey();
const encryptedPayload = await encryptDataWithAES(aesKey, payload);
const encryptedKey = await encryptAESKeyWithRSA(rsaPublicKeyPem, aesKey);
// 发送给服务端的数据结构
return {
key: encryptedKey, // RSA 加密后的 AES 密钥
iv: encryptedPayload.iv,
data: encryptedPayload.data
};
}
// 使用示例
const requestData = { userId: 123, amount: 100.00, timestamp: Date.now() };
encryptRequest(requestData).then(encryptedBody => {
// 发送到 /api/secure-transfer
fetch('/api/secure-transfer', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(encryptedBody)
});
});
服务端解密 (以 Node.js 为例)
使用 Node.js 内置的 crypto 模块。
const crypto = require('crypto');
const fs = require('fs');
// 加载私钥
const privateKey = fs.readFileSync('./private_key.pem', 'utf8');
function decryptRequest(encryptedBody) {
const { key: encryptedKeyB64, iv: ivB64, data: encryptedDataB64 } = encryptedBody;
// 1. 用 RSA 私钥解密 AES 密钥
const decryptedKey = crypto.privateDecrypt(
{
key: privateKey,
padding: crypto.constants.RSA_PKCS1_OAEP_PADDING,
oaepHash: 'sha256'
},
Buffer.from(encryptedKeyB64, 'base64')
);
// 2. 创建 AES 解密器
const decipher = crypto.createDecipheriv(
'aes-256-cbc',
decryptedKey,
Buffer.from(ivB64, 'base64')
);
// 3. 解密数据
let decrypted = decipher.update(Buffer.from(encryptedDataB64, 'base64'));
decrypted = Buffer.concat([decrypted, decipher.final()]);
// 4. 解析 JSON
return JSON.parse(decrypted.toString('utf8'));
}
// 示例 Express 路由
app.post('/api/secure-transfer', (req, res) => {
try {
const originalData = decryptRequest(req.body);
// 正常处理业务逻辑
console.log('解密后的数据:', originalData);
res.json({ status: 'success', data: originalData });
} catch (error) {
console.error('解密失败:', error.message);
res.status(400).json({ status: 'error', message: '解密失败' });
}
});
安全要点 (必须注意)
| 问题 | 解决方案 |
|---|---|
| 中间人攻击 (MITM) | 必须使用 HTTPS,RSA 只加密了 AES 密钥,但公钥分发过程若被篡改,攻击者可以替换自己的公钥。HTTPS 是基础。 |
| RSA 密钥长度 | 建议使用 2048位 或 4096位,4096更安全但加密速度慢。 |
| AES 加密模式 | 推荐 AES-256-GCM (比 CBC 更安全,自带认证标签防止篡改),示例使用了 CBC,如果换成 GCM 需额外处理 authTag。 |
| 初始化向量 (IV) | 必须 随机生成,且每次请求不同。 |
| 填充方式 (Padding) | RSA 使用 OAEP (推荐) 而非 PKCS#1 v1.5,AES 使用标准填充 (PKCS7)。 |
| 重放攻击 (Replay) | 在明文数据中加入 timestamp 和 nonce (一次性随机数),服务端校验时间差和是否已使用过 nonce。 |
| 密钥存储 | 私钥使用环境变量或密钥管理服务 (KMS),不要硬编码在代码里。 |
这套混合加密方案是目前最实用的接口加密方式之一:
- RSA 解决密钥传输的安全问题(无法被窃听)。
- AES 解决大数据的加密效率问题。
- HTTPS 解决身份验证和公钥完整性验证问题。
这三个共同构成了一个相对可靠的加密传输通道。
版权声明:NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播