嘿,大家好!咱们今天聊聊浏览器里的“密码箱”—— Web Cryptography API,看看它怎么帮我们安全地玩转加密和哈希。准备好了吗?Let’s go!
Web Cryptography API 是个啥?
简单来说,Web Cryptography API (简称 Web Crypto API) 是浏览器提供的一套 JavaScript 接口,让开发者可以在客户端(也就是用户的浏览器里)执行各种加密操作,比如生成密钥、加密解密数据、计算哈希值等等。听起来是不是很酷?
为什么要用它?
- 安全第一: 相比于把敏感数据直接明文传输,或者依赖服务器端加密,Web Crypto API 允许我们在浏览器端进行加密,这样即使数据在传输过程中被截获,攻击者看到的也是一堆乱码。
- 减轻服务器压力: 某些加密解密操作可以在客户端完成,可以有效降低服务器的计算负担。
- 离线也能用: 某些情况下,如果需要离线进行数据加密,Web Crypto API 也能派上用场。
Web Crypto API 核心概念
在使用 Web Crypto API 之前,我们需要了解几个关键的概念:
crypto
对象: 这是 Web Crypto API 的入口点,通过window.crypto
可以访问。SubtleCrypto
接口:crypto.subtle
返回一个SubtleCrypto
对象,它提供了加密、解密、签名、验证等各种底层加密操作的方法。CryptoKey
接口: 代表一个加密密钥,可以是公钥、私钥或对称密钥。- 算法 (Algorithms): Web Crypto API 支持多种加密算法,比如 AES, RSA, SHA 等等。每种算法都有自己的参数和用法。
Web Crypto API 支持的算法
Web Crypto API 支持多种对称和非对称加密算法,以及哈希算法。 常见的算法包括:
算法类型 | 算法名称 | 描述 |
---|---|---|
对称加密 | AES-CBC |
高级加密标准,使用密码块链接模式。 |
AES-CTR |
高级加密标准,使用计数器模式。 | |
AES-GCM |
高级加密标准,使用伽罗瓦/计数器模式。 这是最常用的对称加密方式,通常也是最安全的。 | |
AES-KW |
AES 密钥封装,用于安全地封装(加密)密钥。 | |
非对称加密 | RSA-OAEP |
RSA 加密算法,使用最优非对称加密填充 (OAEP) 模式。 |
RSA-PSS |
RSA 签名算法,使用概率签名方案 (PSS)。 | |
RSA-PKCS1-v1_5 |
RSA 加密和签名算法,使用 PKCS#1 v1.5 填充模式。 现在已经很少使用了,安全性有待考量。 | |
ECDSA |
椭圆曲线数字签名算法。 | |
ECDH |
椭圆曲线 Diffie-Hellman 密钥交换算法。 | |
哈希算法 | SHA-1 |
安全哈希算法 1。 已经被认为是不安全的,不推荐使用。 |
SHA-256 |
安全哈希算法 256 位。 推荐使用。 | |
SHA-384 |
安全哈希算法 384 位。 推荐使用。 | |
SHA-512 |
安全哈希算法 512 位。 推荐使用。 | |
HMAC |
密钥哈希消息认证码。 |
Web Crypto API 实战:AES-GCM 加密解密
咱们来一个实际的例子,用 AES-GCM 算法来加密和解密数据。AES-GCM 是一种常用的对称加密算法,安全性较高。
1. 生成密钥 (generateKey)
首先,我们需要生成一个 AES 密钥。
async function generateAESKey() {
return await window.crypto.subtle.generateKey(
{
name: "AES-GCM",
length: 256, // 可以是 128, 192, 或 256
},
true, // 是否可提取密钥
["encrypt", "decrypt"] // 密钥的用途
);
}
这段代码会生成一个 256 位的 AES 密钥,并且允许我们用它来加密和解密数据。
2. 加密 (encrypt)
async function encrypt(key, data) {
const iv = window.crypto.getRandomValues(new Uint8Array(12)); // 初始化向量,长度必须是 12 字节
const encodedData = new TextEncoder().encode(data); // 将字符串转换为 Uint8Array
const ciphertext = await window.crypto.subtle.encrypt(
{
name: "AES-GCM",
iv: iv,
},
key,
encodedData
);
return {
iv: iv,
ciphertext: new Uint8Array(ciphertext),
};
}
这里我们做了几件事:
- 生成一个随机的初始化向量 (IV)。IV 用于增加加密的随机性,防止同样的明文被加密成同样的密文。对于 AES-GCM 来说,IV 的长度必须是 12 字节。
- 将要加密的数据(字符串)转换成
Uint8Array
。 - 使用
crypto.subtle.encrypt()
方法进行加密。 - 返回 IV 和密文。
3. 解密 (decrypt)
async function decrypt(key, iv, ciphertext) {
const decryptedData = await window.crypto.subtle.decrypt(
{
name: "AES-GCM",
iv: iv,
},
key,
ciphertext
);
const decodedData = new TextDecoder().decode(decryptedData); // 将 Uint8Array 转换为字符串
return decodedData;
}
解密过程与加密类似,需要提供密钥、IV 和密文。解密后,我们需要将 Uint8Array
转换回字符串。
4. 完整示例
async function aesGcmExample(data) {
const key = await generateAESKey();
const { iv, ciphertext } = await encrypt(key, data);
const decryptedData = await decrypt(key, iv, ciphertext);
console.log("原始数据:", data);
console.log("密文:", ciphertext);
console.log("解密后的数据:", decryptedData);
if (data === decryptedData) {
console.log("加密解密成功!");
} else {
console.error("加密解密失败!");
}
}
// 调用示例
aesGcmExample("Hello, Web Crypto API!");
运行这段代码,你会在控制台看到原始数据、密文和解密后的数据。如果一切顺利,你会看到“加密解密成功!”的消息。
Web Crypto API 实战:RSA-OAEP 加密解密
接下来,我们来看一个非对称加密的例子,使用 RSA-OAEP 算法。RSA 是一种常用的非对称加密算法,它使用公钥加密,私钥解密。
1. 生成密钥对 (generateKey)
async function generateRSAKeyPair() {
return await window.crypto.subtle.generateKey(
{
name: "RSA-OAEP",
modulusLength: 2048, // 密钥长度,通常是 2048 或 4096
publicExponent: new Uint8Array([0x01, 0x00, 0x01]), // 固定值
hash: "SHA-256", // 使用 SHA-256 哈希算法
},
true, // 是否可提取密钥
["encrypt", "decrypt"] // 密钥的用途
);
}
这段代码会生成一个 RSA 密钥对,包括一个公钥和一个私钥。modulusLength
指定密钥的长度,通常是 2048 或 4096 位。
2. 加密 (encrypt)
async function rsaEncrypt(publicKey, data) {
const encodedData = new TextEncoder().encode(data);
const ciphertext = await window.crypto.subtle.encrypt(
{
name: "RSA-OAEP",
},
publicKey,
encodedData
);
return new Uint8Array(ciphertext);
}
使用公钥加密数据。
3. 解密 (decrypt)
async function rsaDecrypt(privateKey, ciphertext) {
const decryptedData = await window.crypto.subtle.decrypt(
{
name: "RSA-OAEP",
},
privateKey,
ciphertext
);
const decodedData = new TextDecoder().decode(decryptedData);
return decodedData;
}
使用私钥解密数据。
4. 完整示例
async function rsaOaepExample(data) {
const { publicKey, privateKey } = await generateRSAKeyPair();
const ciphertext = await rsaEncrypt(publicKey, data);
const decryptedData = await rsaDecrypt(privateKey, ciphertext);
console.log("原始数据:", data);
console.log("密文:", ciphertext);
console.log("解密后的数据:", decryptedData);
if (data === decryptedData) {
console.log("加密解密成功!");
} else {
console.error("加密解密失败!");
}
}
// 调用示例
rsaOaepExample("Hello, RSA-OAEP!");
运行这段代码,你会看到 RSA 加密解密的结果。
Web Crypto API 实战:哈希 (Hashing)
除了加密解密,Web Crypto API 还可以用来计算哈希值。哈希是一种单向函数,可以将任意长度的数据转换成固定长度的哈希值。哈希值通常用于验证数据的完整性。
async function calculateHash(algorithm, data) {
const encodedData = new TextEncoder().encode(data);
const hashBuffer = await window.crypto.subtle.digest(algorithm, encodedData);
const hashArray = Array.from(new Uint8Array(hashBuffer));
const hashHex = hashArray
.map((b) => b.toString(16).padStart(2, "0"))
.join("");
return hashHex;
}
async function hashExample(data) {
const sha256Hash = await calculateHash("SHA-256", data);
const sha512Hash = await calculateHash("SHA-512", data);
console.log("原始数据:", data);
console.log("SHA-256 哈希值:", sha256Hash);
console.log("SHA-512 哈希值:", sha512Hash);
}
// 调用示例
hashExample("Hello, Hashing!");
这段代码会计算数据的 SHA-256 和 SHA-512 哈希值,并将结果以十六进制字符串的形式输出。
密钥的存储
密钥的存储是个大问题!直接把密钥写在代码里肯定是不行的。Web Crypto API 提供了 exportKey
和 importKey
方法,可以将密钥导出成不同的格式(比如 jwk
、raw
),然后存储在安全的地方(比如浏览器的 IndexedDB
),或者传输到服务器端。
注意事项
- 不要自己发明轮子: Web Crypto API 提供了标准的加密算法,尽量使用这些算法,不要试图自己设计加密算法。
- 随机数很重要: 加密过程中需要使用随机数,Web Crypto API 提供了
window.crypto.getRandomValues()
方法来生成高质量的随机数。 - 密钥管理是关键: 密钥的存储和管理非常重要,一定要采取安全措施,防止密钥泄露。
- HTTPS 是基础: 使用 Web Crypto API 的网站必须使用 HTTPS 协议,否则可能会受到中间人攻击。
- 算法选择: 根据实际需求选择合适的加密算法。AES-GCM 通常用于对称加密,RSA-OAEP 用于非对称加密。SHA-256 和 SHA-512 是常用的哈希算法。
- 错误处理: 加密解密过程中可能会出现错误,比如密钥无效、数据损坏等等。一定要做好错误处理,防止程序崩溃。
- 不要存储用户的密码 使用bcrypt之类的专门hash密码的方案,web crypto api提供的加密方案不适合直接加密密码。
总结
Web Cryptography API 为我们提供了一套强大的工具,可以在浏览器端进行各种加密和哈希操作。但同时也要注意安全问题,正确地使用这些 API,才能真正保护用户的数据安全。
希望今天的讲解对大家有所帮助!如果有什么问题,欢迎随时提问。下次再见!