Security
加密基础 - 对称密钥 vs 非对称密钥:开发者必知必会
如果你不了解AES、RSA和HTTPS的工作原理,请阅读这篇文章。通过实际案例解释加密的核心概念。
Toolypet Team
Development Team
加密基础:对称密钥 vs 非对称密钥
"请把这个数据加密后发送。"
当你听到这句话时,你知道具体该怎么做吗?
加密主要有两种方式。如果不知道何时使用哪种方式,你的安全设计可能会出错。
加密 vs 哈希
首先,让我们区分这两个容易混淆的概念。
| 加密 | 哈希 | |
|---|---|---|
| 方向 | 双向(可解密) | 单向(不可逆) |
| 目的 | 数据保护 | 完整性验证、密码存储 |
| 需要密钥 | 是 | 否 |
| 示例 | AES, RSA | SHA-256, bcrypt |
加密:可以恢复原始数据 哈希:无法恢复原始数据
密码存储使用哈希,数据传输使用加密。
对称密钥加密
概念
使用同一个密钥进行加密和解密。
明文 + 密钥 → 加密 → 密文
密文 + 密钥 → 解密 → 明文
示例:锁和钥匙
想象一下你家的钥匙。用同一把钥匙锁门,也用同一把钥匙开门。
常见算法
| 算法 | 密钥长度 | 状态 |
|---|---|---|
| AES-256 | 256bit | 当前标准 |
| AES-128 | 128bit | 安全 |
| 3DES | 168bit | 遗留系统 |
| DES | 56bit | 已不安全 |
代码示例(Node.js)
const crypto = require('crypto');
// 生成密钥(实际应用中需要安全存储)
const key = crypto.randomBytes(32); // AES-256
const iv = crypto.randomBytes(16); // 初始化向量
// 加密
function encrypt(text) {
const cipher = crypto.createCipheriv('aes-256-cbc', key, iv);
let encrypted = cipher.update(text, 'utf8', 'hex');
encrypted += cipher.final('hex');
return encrypted;
}
// 解密
function decrypt(encrypted) {
const decipher = crypto.createDecipheriv('aes-256-cbc', key, iv);
let decrypted = decipher.update(encrypted, 'hex', 'utf8');
decrypted += decipher.final('utf8');
return decrypted;
}
const secret = "敏感数据";
const encrypted = encrypt(secret);
const decrypted = decrypt(encrypted);
console.log(encrypted); // "a3f8b2c1..."
console.log(decrypted); // "敏感数据"
优缺点
| 优点 | 缺点 |
|---|---|
| 速度快 | 密钥共享问题 |
| 适合大数据 | 密钥泄露则全线崩溃 |
| 实现简单 | 密钥管理复杂 |
密钥共享问题
如果A想向B发送加密消息,A必须先把密钥传给B。
但是,如何安全地传递这个密钥呢?
非对称密钥加密解决了这个问题。
非对称密钥加密
概念
使用两个密钥:
- 公钥(Public Key):任何人都可以知道
- 私钥(Private Key):绝对不能公开
公钥加密 → 只有私钥能解密
私钥签名 → 公钥验证
示例:邮箱
- 公钥 = 邮箱投递口(任何人都可以投递信件)
- 私钥 = 邮箱钥匙(只有主人能取出信件)
常见算法
| 算法 | 用途 | 密钥长度 |
|---|---|---|
| RSA | 加密、签名 | 2048+ bit |
| ECDSA | 签名 | 256+ bit |
| Ed25519 | 签名 | 256bit |
代码示例(Node.js RSA)
const crypto = require('crypto');
// 生成密钥对
const { publicKey, privateKey } = crypto.generateKeyPairSync('rsa', {
modulusLength: 2048,
});
// 公钥加密
function encryptWithPublic(text) {
return crypto.publicEncrypt(publicKey, Buffer.from(text)).toString('base64');
}
// 私钥解密
function decryptWithPrivate(encrypted) {
return crypto.privateDecrypt(privateKey, Buffer.from(encrypted, 'base64')).toString();
}
const secret = "敏感数据";
const encrypted = encryptWithPublic(secret);
const decrypted = decryptWithPrivate(encrypted);
console.log(decrypted); // "敏感数据"
数字签名
用私钥签名后,任何人都可以用公钥验证是谁签名的。
// 私钥签名
const sign = crypto.createSign('SHA256');
sign.update('消息');
const signature = sign.sign(privateKey, 'base64');
// 公钥验证
const verify = crypto.createVerify('SHA256');
verify.update('消息');
const isValid = verify.verify(publicKey, signature, 'base64');
console.log(isValid); // true
优缺点
| 优点 | 缺点 |
|---|---|
| 解决密钥共享问题 | 速度慢(比对称加密慢1000倍) |
| 支持数字签名 | 不适合大数据 |
| 公钥可自由分发 | 密钥长度较长 |
实战:两者结合使用(混合加密)
这就是HTTPS的工作原理。
流程
1. 服务器:生成RSA公钥/私钥对
2. 客户端:获取服务器的公钥
3. 客户端:生成AES会话密钥
4. 客户端:用RSA公钥加密会话密钥 → 发送给服务器
5. 服务器:用RSA私钥解密会话密钥
6. 双方:使用AES会话密钥加密通信
为什么这样做
- RSA:仅用于密钥交换(慢但安全)
- AES:用于实际数据加密(快速)
取两者之长。
实践检查清单
使用对称密钥(AES)时
- 使用AES-256或AES-128
- 每次加密生成新的IV(初始化向量)
- 将密钥存储在环境变量或KMS中
- 禁止使用ECB模式(使用CBC、GCM)
使用非对称密钥(RSA)时
- 至少使用2048bit密钥
- 绝不泄露私钥
- 使用OAEP填充(避免PKCS#1 v1.5)
- 制定密钥轮换策略
常见问题
Q:API密钥应该加密存储吗?
A:建议使用环境变量或密钥管理工具(AWS Secrets Manager、HashiCorp Vault)而不是加密。即使加密了,还是要管理解密密钥。
Q:在客户端加密安全吗?
A:不安全。客户端代码对所有人可见,密钥会暴露。敏感加密应该在服务器端进行。
Q:SHA-256是加密吗?
A:不是。SHA-256是哈希,无法解密。如果需要恢复数据,请使用AES等加密算法。
总结
| 场景 | 使用算法 |
|---|---|
| 大数据加密 | AES-256 |
| 密钥交换 | RSA, ECDH |
| 数字签名 | RSA, ECDSA, Ed25519 |
| 密码存储 | bcrypt, Argon2(哈希) |
| HTTPS通信 | 混合加密(RSA + AES) |
相关工具
加密AESRSAHTTPS安全开发
关于作者
Toolypet Team
Development Team
The Toolypet Team creates free, privacy-focused web tools for developers and designers. All tools run entirely in your browser with no data sent to servers.
Web DevelopmentCSS ToolsDeveloper ToolsSEOSecurity