一、什么是前端加密?(先纠正一个常见误区)
前端加密,指的是在浏览器 (JS 环境) 中,对数据进行加密/签名/混淆/校验等操作,再发送给后端。
重要认知:
前端加密 ≠ 绝对安全
前端代码是可被查看、可被调试、可被篡改的。所以前端加密的核心目的不是防止高手攻击,而是:
- 防止明文传输
- 防止低成本抓包、脚本刷接口
- 提高攻击门槛
- 与后端做配合校验
二、前端常见的加密 [分类]
1. 哈希 (不可逆)
哈希也叫散列,是一种将任意长度的输入(如数据、文件、消息)通过哈希函数转换成固定长度输出的过程,这个输出通常称为哈希值、散列值或摘要。
用途:
- 密码处理
- 签名校验
- 数据完整性校验
常见算法:
- MD5 (已不安全):可人为制造碰撞 (指攻击者找到两个不同的输入,经过哈希计算后,却产生相同的哈希值的过程)
- SHA-1 (不推荐,逐渐被淘汰,存在碰撞攻击)
- SHA-256 和 SHA-512 (推荐,属于 SHA-2),目前广泛应用
示例:
使用 Web Crypto API (crypto.subtle) 进行密码学操作 (需要 HTTPS),也可以使用 CryptoJS JS 的加密库,支持多种加密算法 (AES, SHA, MD5 等)。
// 1. 准备数据
const text = "123456";
const encoder = new TextEncoder();
const data = encoder.encode(text);
// 2. 计算哈希
const hashBuffer = await crypto.subtle.digest('SHA-256', data);
// 3. 转为十六进制
const hashArray = Array.from(new Uint8Array(hashBuffer));
const hashHex = hashArray.map(b => b.toString(16).padStart(2, '0')).join('');
console.log("SHA-256:", hashHex);
// 输出:8d969eef6ecad3c29a3a629280e686cf0c3f5d5a86aff3ca12020c923adc6c92
2. 对称加密 (前后端共用密钥)
特点:
- 加密解密使用同一个 key
- 性能好,适合大量数据
常见算法:
- AES (主流):是目前全球最常用的对称加密算法,美国国家安全局用来保护绝密级信息的算法
- DES (已过时):被破解
示例:
// 最简单的 AES 加密解密
async function aesSimple() {
// 1. 生成密钥
const key = await crypto.subtle.generateKey(
{name: "AES-GCM", length: 256},
true,
["encrypt", "decrypt"]
);
// 2. 加密
const iv = crypto.getRandomValues(new Uint8Array(12));
const encrypted = await crypto.subtle.encrypt(
{name: "AES-GCM", iv},
key,
new TextEncoder().encode("你好世界")
);
// 3. 解密
const decrypted = await crypto.subtle.decrypt(
{name: "AES-GCM", iv},
key,
encrypted
);
console.log("结果:", new TextDecoder().decode(decrypted)); // 你好世界
}
aesSimple();
3. 非对称加密 (公钥/私钥)
先用它安全的交换对称密钥,然后用对称加密处理数据!
特点:
- 前端:公钥加密
- 后端:私钥解密
- 私钥不暴露
适合:
- 密码
- 关键字段
- 初始密钥交换
缺点:
- 慢
- 不适合大量数据
常见算法: ECC (更安全,少见) 加密原理来自于椭圆双曲线。
// ECC 密钥交换完整流程演示
class ECCFlow {
static async demonstrateCompleteFlow() {
console.log("ECC 密钥交换完整流程演示");
console.log("==========================");
// 第 1 步:选择椭圆曲线
console.log("\n第 1 步:选择椭圆曲线");
const curve = "P-256";
console.log(" 选择的曲线:" + curve);
console.log(" 安全强度:128 位");
console.log(" 公钥长度:65 字节");
console.log(" 私钥长度:32 字节");
// 第 2 步:双方生成密钥对
console.log("\n第 2 步:双方生成密钥对");
// Alice 生成密钥对
const aliceKeyPair = await crypto.subtle.generateKey(
{ name: "ECDH", namedCurve: curve },
true,
["deriveKey"]
);
console.log(" Alice 生成密钥对:");
console.log(" - 私钥:保密存储");
console.log(" - 公钥:准备发送给 Bob");
// Bob 生成密钥对
const bobKeyPair = await crypto.subtle.generateKey(
{ name: "ECDH", namedCurve: curve },
true,
["deriveKey"]
);
console.log(" Bob 生成密钥对:");
console.log(" - 私钥:保密存储");
console.log(" - 公钥:准备发送给 Alice");
// 第 3 步:交换公钥
console.log("\n第 3 步:交换公钥(通过网络)");
const bobPublicKey = bobKeyPair.publicKey;
console.log(" Alice 收到 Bob 的公钥");
const alicePublicKey = aliceKeyPair.publicKey;
console.log(" Bob 收到 Alice 的公钥");
// 第 4 步:计算共享密钥
console.log("\n第 4 步:各自计算共享密钥");
console.log(" 数学原理:");
console.log(" Alice 私钥 × Bob 公钥 = Bob 私钥 × Alice 公钥");
// Alice 计算共享密钥
const aliceSharedKey = await crypto.subtle.deriveKey(
{ name: "ECDH", public: bobPublicKey },
aliceKeyPair.privateKey,
{ name: "AES-GCM", length: 256 },
true,
["encrypt", "decrypt"]
);
console.log(" Alice 计算共享密钥完成");
// Bob 计算共享密钥
const bobSharedKey = await crypto.subtle.deriveKey(
{ name: "ECDH", public: alicePublicKey },
bobKeyPair.privateKey,
{ name: "AES-GCM", length: 256 },
true,
["encrypt", "decrypt"]
);
console.log(" Bob 计算共享密钥完成");
// 第 5 步:验证密钥相同
console.log("\n第 5 步:验证双方密钥相同");
const aliceKeyBytes = await crypto.subtle.exportKey("raw", aliceSharedKey);
const bobKeyBytes = await crypto.subtle.exportKey("raw", bobSharedKey);
const aliceHex = Array.from(new Uint8Array(aliceKeyBytes))
.map(b => b.toString(16).padStart(2, '0'))
.join('');
const bobHex = Array.from(new Uint8Array(bobKeyBytes))
.map(b => b.toString(16).padStart(2, '0'))
.join('');
console.log(" 验证结果:");
console.log(" Alice 密钥:" + aliceHex.substring(0, 32) + "...");
console.log(" Bob 密钥:" + bobHex.substring(0, 32) + "...");
console.log(" 是否相同:" + (aliceHex === bobHex ? "是" : "否"));
// 第 6 步:使用共享密钥加密通信
console.log("\n第 6 步:使用共享密钥加密通信");
const message = "会议时间改为下午 2 点";
console.log(" Alice 要发送:\"" + message + "\"");
// 加密
const iv = crypto.getRandomValues(new Uint8Array(12));
const encrypted = await crypto.subtle.encrypt(
{ name: "AES-GCM", iv },
aliceSharedKey,
new TextEncoder().encode(message)
);
console.log(" 加密完成:");
console.log(" - 密文长度:" + encrypted.byteLength + " 字节");
console.log(" - IV: " + Array.from(iv).slice(0, 3).join(',') + "...");
// 第 7 步:Bob 解密消息
console.log("\n第 7 步:Bob 解密消息");
const decrypted = await crypto.subtle.decrypt(
{ name: "AES-GCM", iv },
bobSharedKey,
encrypted
);
const decryptedMessage = new TextDecoder().decode(decrypted);
console.log(" Bob 解密得到:\"" + decryptedMessage + "\"");
console.log(" 是否正确:" + (message === decryptedMessage ? "是" : "否"));
// 安全性分析
console.log("\n安全性分析:");
console.log(" 中间人无法计算共享密钥");
console.log(" 即使窃听到公钥交换也没用");
console.log(" 每次会话可生成新的密钥对");
return { aliceKeyPair, bobKeyPair, sharedKey: aliceSharedKey, encryptedMessage: encrypted };
}
}
// 运行完整流程
ECCFlow.demonstrateCompleteFlow().catch(console.error);
4. 非对称加密和对称加密对比
RSA (最常见):原理来自于大数的质因数分解。
async function generateRSAKeys() {
// 生成 RSA 密钥对
const keyPair = await crypto.subtle.generateKey(
{
name: "RSA-OAEP", // RSA 算法
modulusLength: 2048, // 2048 位
publicExponent: new Uint8Array([0x01, 0x00, 0x01]), // 65537
hash: "SHA-256" // 使用的哈希
},
true, // 可导出
["encrypt", "decrypt"] // 用途
);
return { publicKey: keyPair.publicKey, privateKey: keyPair.privateKey };
}
async function rsaEncryptDecrypt() {
console.log("=== RSA 加密解密示例 ===");
// 1. 生成密钥对
const { publicKey, privateKey } = await generateRSAKeys();
console.log("密钥对生成完成");
// 2. 准备要加密的数据
const message = "这是一条秘密消息";
const data = new TextEncoder().encode(message);
// 3. 用公钥加密
const encrypted = await crypto.subtle.encrypt(
{ name: "RSA-OAEP" },
publicKey,
data
);
console.log("加密完成,密文长度:", encrypted.byteLength, "字节");
// 4. 用私钥解密
const decrypted = await crypto.subtle.decrypt(
{ name: "RSA-OAEP" },
privateKey,
encrypted
);
const decryptedMessage = new TextDecoder().decode(decrypted);
console.log("解密结果:", decryptedMessage);
return { publicKey, privateKey, encrypted };
}
// 运行示例
rsaEncryptDecrypt().catch(console.error);
| 特性 | 对称加密 | 非对称加密 |
|---|---|---|
| 密钥数量 | 单个密钥,加解密相同。 | 一对密钥,公钥加密,私钥解密。 |
| 速度 | 非常快,适合加密大量数据。 | 非常慢(比对称加密慢 100-1000 倍),不适合大数据。 |
| 安全性基础 | 密钥的保密性。密钥必须安全共享。 | 密钥对的数学关系。私钥保密,公钥可公开。 |
| 主要功能 | 保证数据的机密性。 | 保证机密性、身份认证和不可否认性。 |
| 密钥分发 | 核心难题。如何安全地将密钥传递给对方? | 天然解决。公钥可以公开分发,无需保密。 |
| 常见算法 | AES(高级加密标准)、DES、3DES、ChaCha20 | RSA、ECC(椭圆曲线加密)、ElGamal |
| 典型应用 | 文件加密、数据库加密、SSL/TLS 会话加密、Wi-Fi(WPA2) | SSL/TLS 密钥交换、数字签名、电子邮件加密(PGP)、区块链 |
5. 签名≠加密
签名的本质是:证明数据是'你'发的,且未被篡改。
常见做法:
sign = hash(params + secret + timestamp)
//前端
sign = sha256(a=1&b=2&secret=xxx&ts=123
后端:
- 用同样规则计算
- 对比 sign 是否一致
三、前端加密的底线原则
- 前端加密永远不是安全的终点
- 所有安全校验,必须在后端完成
- 前端加密的价值是:降低成本攻击,而不是消灭攻击
- 真正的安全 = https + 前端处理 + 后端校验 + 风控策略

