探索 Web Crypto API,这是一种在浏览器中直接执行加密操作的强大工具。通过实际示例了解哈希、加密、签名和密钥管理。
Web Crypto API:加密操作综合指南
Web Crypto API 是一个 JavaScript API,允许开发人员直接在浏览器中执行加密操作。 这为构建安全的 Web 应用程序开辟了可能性,而无需依赖服务器端处理来执行敏感任务。 本文提供了 Web Crypto API 的全面概述,涵盖其主要功能、用例和最佳实践。
浏览器中的密码学简介
传统上,由于安全问题和客户端 JavaScript 的限制,加密操作主要在服务器端处理。 但是,Web Crypto API 提供了一种安全且标准化的方式来直接在浏览器中执行加密任务。 这启用了一系列新功能,例如客户端加密、安全身份验证和数字签名,所有这些都无需将敏感数据不必要地传输到服务器。
客户端密码学的一个主要优势是减少了服务器负载。 通过将加密计算卸载到浏览器,服务器可以专注于其他任务,从而提高整体应用程序性能。 此外,客户端加密可以通过确保敏感数据在离开用户设备之前进行加密来增强用户隐私。
Web Crypto API 的核心概念
Web Crypto API 基于以下核心概念:
- 密码学算法:该 API 支持各种密码学算法,包括对称加密(例如 AES)、非对称加密(例如 RSA)、哈希算法(例如 SHA-256)和数字签名算法(例如 ECDSA)。
- 密钥:加密操作通常需要密钥。 Web Crypto API 提供了安全地生成、导入、导出和存储密钥的机制。 密钥可以是对称的(用于加密和解密)或非对称的(由公钥和私钥组成)。
- SubtleCrypto 接口:
SubtleCrypto接口是访问加密函数的主要入口点。 它提供了执行哈希、加密、解密、签名和验证的方法。 - Promises:Web Crypto API 中的所有加密操作都是异步的并且返回 promise。 这确保了浏览器的 UI 在执行可能耗时的加密任务时保持响应。
支持的密码学算法
Web Crypto API 支持各种密码学算法。 以下是一些最常用的算法:
对称加密
- AES(高级加密标准):一种广泛使用的对称加密算法。 Web Crypto API 支持 AES-CBC、AES-CTR、AES-GCM 和 AES-KW 模式。
非对称加密
- RSA(Rivest-Shamir-Adleman):一种流行的非对称加密算法。 Web Crypto API 支持 RSA-OAEP 和 RSA-PSS 填充方案。
- ECDSA(椭圆曲线数字签名算法):一种基于椭圆曲线密码学的非对称签名算法。
- ECDH(椭圆曲线 Diffie-Hellman):一种基于椭圆曲线密码学的密钥协商协议。
哈希算法
- SHA-256(安全哈希算法 256 位):一种广泛使用的哈希算法,可生成 256 位哈希值。
- SHA-384(安全哈希算法 384 位):一种生成 384 位哈希值的哈希算法。
- SHA-512(安全哈希算法 512 位):一种生成 512 位哈希值的哈希算法。
基本加密操作
让我们通过代码示例探索使用 Web Crypto API 的一些基本加密操作。
哈希
哈希是将数据转换为固定大小的字符串(哈希值)的过程。 哈希用于数据完整性检查、密码存储和索引。
async function hashData(data) {
const encoder = new TextEncoder();
const dataBuffer = encoder.encode(data);
const hashBuffer = await crypto.subtle.digest('SHA-256', dataBuffer);
const hashArray = Array.from(new Uint8Array(hashBuffer));
const hashHex = hashArray
.map((b) => b.toString(16).padStart(2, '0'))
.join('');
return hashHex;
}
// Example usage:
hashData('Hello, world!')
.then((hash) => console.log('SHA-256 Hash:', hash))
.catch((err) => console.error('Hashing error:', err));
生成对称密钥
对称密钥用于使用同一密钥进行加密和解密。 Web Crypto API 允许您使用 generateKey() 方法生成对称密钥。
async function generateAESKey() {
return await crypto.subtle.generateKey(
{
name: 'AES-GCM',
length: 256,
},
true, // extractable
['encrypt', 'decrypt'] // usages
);
}
// Example usage:
generateAESKey()
.then((key) => {
console.log('AES Key generated:', key);
// Use the key for encryption/decryption
})
.catch((err) => console.error('Key generation error:', err));
加密数据
加密是将数据转换为不可读格式以保护其机密性的过程。 这是一个使用 AES-GCM 加密数据的示例:
async function encryptData(key, data) {
const encoder = new TextEncoder();
const dataBuffer = encoder.encode(data);
const iv = crypto.getRandomValues(new Uint8Array(12)); // Initialization vector
const encryptedData = await crypto.subtle.encrypt(
{
name: 'AES-GCM',
iv: iv,
},
key,
dataBuffer
);
// Combine IV and encrypted data for storage/transmission
const combined = new Uint8Array(iv.length + encryptedData.byteLength);
combined.set(iv, 0);
combined.set(new Uint8Array(encryptedData), iv.length);
return combined;
}
// Example usage (assuming you have an AES key):
generateAESKey().then(key => {
encryptData(key, 'Sensitive data')
.then((encrypted) => {
console.log('Encrypted data:', encrypted);
})
.catch((err) => console.error('Encryption error:', err));
});
解密数据
解密是将加密数据转换回其原始可读格式的过程。 这是一个解密使用 AES-GCM 加密的数据的示例:
async function decryptData(key, combined) {
const iv = combined.slice(0, 12);
const encryptedData = combined.slice(12);
const decryptedData = await crypto.subtle.decrypt(
{
name: 'AES-GCM',
iv: iv,
},
key,
encryptedData
);
const decoder = new TextDecoder();
return decoder.decode(decryptedData);
}
// Example usage (assuming you have the AES key and encrypted data):
generateAESKey().then(key => {
encryptData(key, 'Sensitive data').then(encrypted => {
decryptData(key, encrypted)
.then((decrypted) => {
console.log('Decrypted data:', decrypted);
})
.catch((err) => console.error('Decryption error:', err));
});
});
生成非对称密钥
非对称密钥由公钥和私钥组成。 公钥可以与他人共享,而私钥必须保密。 Web Crypto API 支持使用 generateKey() 方法生成非对称密钥。
async function generateRSAKey() {
return await crypto.subtle.generateKey(
{
name: 'RSA-OAEP',
modulusLength: 2048, // The length of the key in bits
publicExponent: new Uint8Array([0x01, 0x00, 0x01]), // Commonly 65537
hash: 'SHA-256',
},
true, // extractable
['encrypt', 'decrypt'] // usages
);
}
// Example usage:
generateRSAKey()
.then((keyPair) => {
console.log('RSA Public Key:', keyPair.publicKey);
console.log('RSA Private Key:', keyPair.privateKey);
// Use the keys for encryption/decryption
})
.catch((err) => console.error('Key generation error:', err));
签名数据
数字签名用于验证数据的真实性和完整性。 发送者使用其私钥对数据进行签名,接收者使用发送者的公钥验证签名。
async function signData(privateKey, data) {
const encoder = new TextEncoder();
const dataBuffer = encoder.encode(data);
const signature = await crypto.subtle.sign(
{
name: 'RSASSA-PKCS1-v1_5',
hash: { name: 'SHA-256' },
},
privateKey,
dataBuffer
);
return signature;
}
// Example usage (assuming you have an RSA key pair):
generateRSAKey().then(keyPair => {
signData(keyPair.privateKey, 'Data to sign')
.then((signature) => {
console.log('Signature:', signature);
})
.catch((err) => console.error('Signing error:', err));
});
验证签名
验证数字签名可确认数据未被篡改,并且确实是由声称的发送者签名的。
async function verifySignature(publicKey, signature, data) {
const encoder = new TextEncoder();
const dataBuffer = encoder.encode(data);
const isValid = await crypto.subtle.verify(
{
name: 'RSASSA-PKCS1-v1_5',
hash: { name: 'SHA-256' },
},
publicKey,
signature,
dataBuffer
);
return isValid;
}
// Example usage (assuming you have the RSA key pair and the signature):
generateRSAKey().then(keyPair => {
signData(keyPair.privateKey, 'Data to sign').then(signature => {
verifySignature(keyPair.publicKey, signature, 'Data to sign')
.then((isValid) => {
console.log('Signature is valid:', isValid);
})
.catch((err) => console.error('Verification error:', err));
});
});
密钥管理
适当的密钥管理对于任何密码系统的安全至关重要。 Web Crypto API 提供了安全地生成、导入、导出和存储密钥的机制。 但是,在浏览器中安全地存储密钥可能具有挑战性。
密钥存储注意事项
- IndexedDB:一种选择是将密钥存储在 IndexedDB 中,这是一个基于浏览器的 NoSQL 数据库。 但是,IndexedDB 并非专门为安全密钥存储而设计,因此实施额外的安全措施(例如在存储密钥之前对其进行加密)非常重要。
- LocalStorage/Cookies:通常不建议使用这些方法来存储加密密钥,因为它们的安全功能有限,并且存在跨站点脚本 (XSS) 攻击的可能性。
- 硬件安全模块 (HSM):在更高级的场景中,您可以使用浏览器扩展程序或本机应用程序来与硬件安全模块 (HSM) 交互,以实现安全密钥存储和加密操作。
密钥导入和导出
Web Crypto API 允许您以各种格式导入和导出密钥,例如:
- JWK(JSON Web Key):一种基于 JSON 的格式,用于表示加密密钥。
- PKCS#8:一种用于存储私钥的标准格式。
- SPKI(主题公钥信息):一种用于存储公钥的标准格式。
导入和导出密钥对于在不同系统之间传输密钥或备份密钥非常有用。
密钥包装和解包
密钥包装是用另一个密钥(包装密钥)加密密钥的过程。 这可用于保护密钥在存储或传输时的安全。 Web Crypto API 支持使用 AES-KW 和 RSA-OAEP 等算法进行密钥包装和解包。
Web Crypto API 的用例
Web Crypto API 为构建安全的 Web 应用程序开辟了广阔的可能性。 以下是一些常见的用例:
- 客户端加密:在将敏感数据发送到服务器之前,在浏览器中对其进行加密。 这可以保护数据免受窃听和未经授权的访问。
- 安全身份验证:使用数字签名和密钥交换协议实现安全身份验证机制。
- 数据完整性检查:使用哈希算法来验证从服务器下载的数据的完整性。
- 安全通信:使用加密和密钥交换协议建立安全通信通道。
- 数字版权管理 (DRM):实施 DRM 方案以保护受版权保护的内容。
- 密码管理:实施安全密码存储和检索机制。 在将密码发送到服务器之前,使用 PBKDF2 在客户端对密码进行哈希处理。
安全注意事项
虽然 Web Crypto API 提供了一个构建安全的 Web 应用程序的强大工具,但重要的是要注意潜在的安全风险并遵循最佳实践:
- 跨站点脚本 (XSS):XSS 攻击会危及应用程序的安全性,并允许攻击者窃取敏感数据,包括加密密钥。 通过正确清理用户输入和使用内容安全策略 (CSP) 来保护您的应用程序免受 XSS 攻击。
- 中间人 (MITM) 攻击:MITM 攻击会拦截和修改网络流量,从而可能危及数据的机密性和完整性。 通过使用 HTTPS 并验证服务器证书的真实性来保护您的应用程序免受 MITM 攻击。
- 侧信道攻击:侧信道攻击利用在加密操作期间泄露的信息(例如时序变化或功耗)来恢复密钥。 Web Crypto API 旨在缓解侧信道攻击,但重要的是要注意此风险并使用密码学实施的最佳实践。
- 密钥管理:安全的密钥管理对于任何密码系统的安全至关重要。 保护您的密钥免受未经授权的访问,并确保它们得到安全地存储和处理。
- 算法选择:选择适合您的安全要求的密码学算法和密钥大小。 避免使用弱或过时的算法。 咨询安全专家以确定适合您应用程序的最佳算法。
- 定期更新:使您的浏览器和 JavaScript 库保持最新,并安装最新的安全补丁。 这些组件中的漏洞会危及您的应用程序的安全性。
使用 Web Crypto API 的最佳实践
以下是使用 Web Crypto API 的一些最佳实践:
- 使用 HTTPS:始终使用 HTTPS 来保护您的应用程序免受 MITM 攻击。
- 清理用户输入:正确清理用户输入以防止 XSS 攻击。
- 使用内容安全策略 (CSP):使用 CSP 来限制您的应用程序可以加载的资源,从而降低 XSS 攻击的风险。
- 选择强大的算法:选择适合您的安全要求的强大密码学算法和密钥大小。
- 实施安全密钥管理:实施安全密钥管理实践来保护您的密钥免受未经授权的访问。
- 使您的软件保持最新:使您的浏览器和 JavaScript 库保持最新,并安装最新的安全补丁。
- 彻底测试您的应用程序:彻底测试您的应用程序以识别和修复潜在的安全漏洞。
- 考虑使用密码学库:虽然 Web Crypto API 功能强大,但使用经过充分测试的密码学库(如 TweetNaCl.js 或 CryptoJS)可以提供额外的安全性和便利性。 这些库通常处理低级细节和边缘情况,从而降低出错的风险。
Web Crypto API 在实践中的示例
让我们考虑几个实际示例,其中可以使用 Web Crypto API 来增强安全性和隐私:
安全消息传递应用程序
安全消息传递应用程序可以使用 Web Crypto API 在客户端加密消息,然后再将它们发送到服务器。 这确保只有预期的收件人才能阅读消息,即使服务器受到威胁。 用户可以生成密钥对,使用收件人的公钥加密消息,并使用自己的私钥对消息进行签名。 然后,收件人将使用其私钥解密消息,并使用其公钥验证发件人的签名。
安全文件存储
安全文件存储应用程序可以使用 Web Crypto API 在客户端加密文件,然后再将它们上传到服务器。 这可以保护文件免受未经授权的访问,即使服务器受到威胁。 用户可以生成加密密钥,使用这些密钥加密文件,然后安全地存储加密文件以及密钥(可能包装密钥以增加保护)。 当用户想要访问文件时,应用程序将检索加密文件和相应的密钥,在客户端解密文件,然后将其显示给用户。
高级主题
除了基本知识之外,Web Crypto API 还提供了一些高级功能,用于专门的用例:
- 密钥派生函数 (KDF):KDF 用于从密码或其他秘密值派生加密密钥。 Web Crypto API 支持 PBKDF2(基于密码的密钥派生函数 2),这是一种广泛使用的 KDF,用于基于密码的密钥派生。
- 身份验证加密:身份验证加密算法(如 AES-GCM 和 ChaCha20-Poly1305)既提供机密性又提供完整性。 它们加密数据,还生成一个身份验证标记,该标记可用于验证数据的完整性。
- 椭圆曲线密码学 (ECC):ECC 是一种基于椭圆曲线的非对称密码学。 Web Crypto API 支持 ECDSA(椭圆曲线数字签名算法)和 ECDH(椭圆曲线 Diffie-Hellman),它们通常用于数字签名和密钥交换。
结论
Web Crypto API 提供了一种强大且标准化的方式来直接在浏览器中执行加密操作。 这使开发人员能够构建安全的 Web 应用程序,而无需依赖服务器端处理来执行敏感任务。 通过了解 Web Crypto API 的核心概念,遵循最佳实践并了解潜在的安全风险,您可以利用这个强大的工具来增强 Web 应用程序的安全性和隐私。 随着 Web 应用程序变得越来越复杂并处理更多敏感数据,Web Crypto API 将在确保 Web 的安全性和隐私方面发挥越来越重要的作用。