关于混合加密(AES+RSA)
关于混合加密(AES+RSA)
1、裸奔的网络请求
应用程序或系统在进行网络通信(如 HTTP/HTTPS 请求、API 调用)时,直接以明文(未加密)的形式发送和接收敏感数据。
这时我们传输的任何数据被抓包工具轻松获取。即使在测试环境,也可能丢失重要信息和敏感信息。
例如,测试数据中混入了自己的电话号码,姓名,常用的街道地址,公司地址等。
生产环境如果不加密请求和响应数据,将会对信息系统造成不可挽回的损失:
- 1、窃听 (Sniffing/Eavesdropping): 攻击者位于同一网络(如公共 Wi-Fi)或网络路径上,使用抓包工具(如 Wireshark)可以轻易捕获所有明文传输的数据。
- 2、中间人攻击 (MITM): 攻击者插入到通信双方之间,不仅能窃听,还能篡改请求或响应内容(如将收款账号改成攻击者的),甚至冒充服务器或客户端。
- 3、数据泄露: 服务器或数据库如果存储了这些明文数据,一旦被入侵,所有用户信息将完全暴露。
- 4、不符合合规要求: 几乎所有数据隐私法规(如 GDPR, CCPA, HIPAA)都要求对敏感数据进行加密传输和存储。
2、对称加密,非对称加密的特点
特性 | 对称加密 (如 AES, DES, 3DES, ChaCha20) | 非对称加密 (如 RSA, ECC, ElGamal) |
---|---|---|
密钥数量 | 单密钥:加密和解密使用同一个密钥。 | 密钥对:使用公钥和私钥组成的密钥对。 |
密钥分发 | 困难且风险高:安全地将密钥传递给通信双方是主要挑战。 | 相对简单:公钥可以公开分发(如通过证书),私钥严格保密。 |
速度 | 非常快:算法设计高效,适合加密大量数据。 | 相对慢:算法涉及复杂数学运算(大数分解、离散对数等),比对称加密慢几个数量级。 |
主要用途 | 加密大量数据(文件、消息体、数据库内容、通信流)。 | 安全交换对称密钥、数字签名、身份认证。 |
算法示例 | AES-128, AES-256, ChaCha20-Poly1305 | RSA (2048/4096位), ECC (secp256k1, Curve25519) |
优点 | 速度快,效率高,适合大数据块。 | 解决了安全密钥分发问题,支持数字签名和身份认证。 |
缺点 | 密钥分发困难,管理大量密钥复杂,缺乏原生认证/签名功能。 | 速度慢,不适合直接加密大量数据。 |
只使用对称加密:由于只使用一个密钥加密,只要加密密钥在客户端或者服务端任何一处泄露,黑客都可以轻松获取服务器和客户端的所有请求明文。
只使用非对称加密:加密效率太低,影响系统性能。
3、混合加密
混合加密技术巧妙地结合了对称加密和非对称加密的优点,克服了各自的缺点,成为现代安全通信(如 HTTPS/TLS, PGP/GPG)的核心机制。
3.1 核心思想
用对称加密(AES)保护数据本身: 利用其速度快、效率高的优势加密实际要传输的大量数据(消息体、文件)。
用非对称加密(RSA)保护对称密钥: 利用其安全的密钥分发能力,将用于对称加密的那个临时密钥(会话密钥) 安全地传递给接收方。
3.2 详细流程(以客户端发送加密数据给服务器为例)
1、生成临时对称密钥: 发送方(客户端)随机生成一个对称密钥(称为会话密钥或数据加密密钥 - DEK)。这个密钥是临时的,通常仅用于本次通信会话或单个文件。
2、对称加密数据: 发送方使用这个会话密钥 (AES Key) 和强大的对称加密算法(如 AES-256)加密要发送的实际数据(明文),得到密文数据。
3、获取接收方公钥: 发送方获取接收方(服务器)的公钥。这通常通过受信任的渠道完成,例如服务器的数字证书(在 HTTPS 握手过程中获取)。
4、非对称加密会话密钥: 发送方使用接收方的公钥 (RSA Public Key) 对第一步生成的会话密钥 (AES Key) 进行加密,得到加密的会话密钥。
5、发送组合数据: 发送方将加密的会话密钥和密文数据一起发送给接收方。
6、接收方解密会话密钥: 接收方收到数据包后,用自己的私钥 (RSA Private Key) 解密收到的加密的会话密钥,还原出原始的会话密钥 (AES Key)。只有拥有对应私钥的接收方才能完成这一步。
7、接收方解密数据: 接收方使用还原出来的会话密钥 (AES Key) 和对称加密算法(如 AES-256)解密收到的密文数据,得到原始的明文数据。
+-----------------+ +-----------------+
| 发送方 | | 接收方 |
| (例如: 客户端) | | (例如: 服务器) |
+-----------------+ +-----------------+
| |
| 1. 随机生成 AES 会话密钥 |
|----------------------------->
| |
| 2. 用 AES Key 加密数据 |
| (明文数据 -> 密文数据) |
| |
| 3. 获取接收方公钥 (RSA Pub) |
| |
| 4. 用 RSA Pub 加密 AES Key |
| (AES Key -> 加密的AES Key) |
| |
| 5. 发送 [加密的AES Key] + |
| [密文数据] |
|----------------------------->|
| | 6. 用 RSA 私钥解密
| | [加密的AES Key] -> AES Key
| |
| | 7. 用 AES Key 解密
| | [密文数据] -> 明文数据
| |
+-----------------+ +-----------------+
3.3 混合加密的优势
结合优点:
利用了对称加密的速度(加密数据块)。
利用了非对称加密的安全密钥分发(传递会话密钥)。
解决关键问题: 完美解决了对称加密中密钥安全分发的难题。
高效安全: 即使需要传输海量数据,也能在保证安全性的前提下维持高效性能。
前向保密 (Perfect Forward Secrecy - PFS) 的基础: 混合加密是实现 PFS 的关键。每次会话使用唯一、临时的 AES 会话密钥,即使服务器的长期 RSA 私钥在未来被泄露,也无法解密过去捕获的通信记录(因为每次用的 AES Key 不同且未存储)。现代 TLS 通常使用 ECDHE(基于 ECC 的临时密钥交换)结合 RSA 签名来协商 AES 会话密钥,实现 PFS。
广泛应用: HTTPS (TLS/SSL)、SSH、PGP/GPG 文件加密、安全消息应用等。
3.4 原理总结
混合加密(AES + RSA)是一种优雅且强大的安全实践。它让快速高效的对称加密(AES)负责繁重的数据加密工作,而让专长于安全密钥管理和身份认证的非对称加密(RSA)负责安全地传递那个关键的对称密钥。这种分工协作的方式,使得在开放的互联网上安全、高效地传输大量数据成为可能,是构建现代网络安全通信的基石。它相当于给数据本身加了一把牢固的锁(AES),然后把这把锁的钥匙(AES Key)用一个特制的保险箱(RSA公钥加密)安全地寄给对方,只有对方有打开保险箱的密码(RSA私钥)。
4.4 后端实现
以 Express 服务端为例:
4.1 密钥的生成
AES对称密钥可以在代码运行时生成,其实就是一个128位或者256位的字符串。
RSA 加密的公钥和密钥需要借助SSL工具生成。 一般使用openssl即可。
你可以使用 openssl 工具在本地生成 RSA 密钥对(公钥和私钥),步骤如下:
- 生成私钥(private key)
openssl genpkey -algorithm RSA -out private.pem -pkeyopt rsa_keygen_bits:2048
- 生成公钥(public key)
openssl rsa -in private.pem -pubout -out public.pem
- 查看和复制密钥内容
用文本编辑器打开 private.pem 和 public.pem,将内容分别粘贴到你的 加密工具类文件对应位置(注意保留头尾的 -----BEGIN ... KEY----- 和 -----END ... KEY-----)。 - 安全建议
私钥(private.pem)只保存在服务器端,切勿泄露。
公钥(public.pem)可以安全地分发给前端或其他需要加密数据的客户端。
4.2 密钥不建议直接写在源代码中,更安全的存储和管理方式有:
1、环境变量(Environment Variables)
将密钥内容存储在环境变量中,代码中通过 process.env 读取。例如:
const RSA_PRIVATE_KEY = process.env.RSA_PRIVATE_KEY;
2、启动服务时通过 .env 文件或 shell 传递密钥。
const fs = require('fs');
const RSA_PRIVATE_KEY = fs.readFileSync('/path/to/private.pem', 'utf8');
3、配置文件(Config Files)
将密钥单独存放在配置文件(如 private.pem),代码运行时读取文件内容:
配置文件权限应严格限制,仅服务进程可读。
4、密钥管理服务(KMS)
使用云服务(如 AWS KMS、阿里云 KMS、Azure Key Vault)集中管理密钥,应用启动时动态获取密钥。
5、操作系统安全存储
如 macOS Keychain、Windows Credential Manager、Linux Secret Service 等。
6、容器/编排平台的密钥管理
如 Docker secrets、Kubernetes secrets,将密钥挂载为只读文件或环境变量。
推荐做法:
开发环境可用 .env 文件,生产环境建议用配置文件+权限控制或 KMS,不要将密钥提交到代码仓库。
5、关于第三方工具测试请求的方法
5.1 模拟请求流程
你可以用 Postman 模拟加密接口,流程如下:
步骤一:准备密钥
从 public.pem 复制公钥内容。
步骤二:生成随机 AES 密钥
用 Node.js 脚本生成 32 字节 AES 密钥(如:crypto.randomBytes(32))。
步骤三:用 AES 密钥加密请求数据
用 AES-256-CBC 加密你的 JSON 数据,生成 iv 和 data。
步骤四:用公钥加密 AES 密钥
用 RSA 公钥加密上一步生成的 AES 密钥,得到 encryptedKey。
步骤五:构造 Postman 请求
请求体(JSON 格式)如下:
{
"encryptedKey": "(RSA加密后的AES密钥,base64字符串)",
"encryptedData": {
"iv": "(AES加密用的iv,base64字符串)",
"data": "(AES加密后的数据,base64字符串)"
}
}
步骤六:发送请求
Content-Type 设为 application/json,直接发送即可。
5.2 生成postman 请求体的脚本
const crypto = require('crypto');
const fs = require('fs');
const publicKey = fs.readFileSync('./src/keys/public.pem', 'utf8');
const data = JSON.stringify({ username: 'test', password: '123456' });
// 1. 生成随机AES密钥
const aesKey = crypto.randomBytes(32);
// 2. AES加密数据
const iv = crypto.randomBytes(16);
const cipher = crypto.createCipheriv('aes-256-cbc', aesKey, iv);
let encrypted = cipher.update(data, 'utf8', 'base64');
encrypted += cipher.final('base64');
// 3. 用公钥加密AES密钥
const encryptedKey = crypto.publicEncrypt(
{ key: publicKey, padding: crypto.constants.RSA_PKCS1_PADDING },
aesKey
).toString('base64');
// 4. 打印Postman请求体
console.log(JSON.stringify({
encryptedKey,
encryptedData: {
iv: iv.toString('base64'),
data: encrypted
}
}, null, 2));