Web Crypto API 是当前最可靠、浏览器原生支持的前端加密方案。它由 W3C 标准化,运行于安全上下文,密钥抽象为不可导出的 CryptoKey 对象,强制安全参数与异步操作,避免内存泄露和误用风险。

JavaScript 中实现加密和解密,Web Crypto API 是当前最可靠、浏览器原生支持的方案。它由 W3C 标准化,运行在安全上下文(HTTPS 或 localhost)中,密钥不会暴露在 JavaScript 内存里,避免了传统库(如 CryptoJS)手动实现易出错、缺乏密钥隔离等风险。
为什么不用第三方加密库?
像 CryptoJS、SJCL 这类纯 JS 实现的库,虽然用法简单,但存在明显短板:
- 算法依赖开发者手动组合,容易误用(比如用 ECB 模式加密敏感数据)
- 密钥以字符串或字节数组形式存在于 JS 堆内存,可能被恶意脚本读取或通过内存快照泄露
- 不支持硬件级密钥保护(如 Secure Enclave、TPM),也无法与浏览器密码管理器、操作系统密钥链联动
- 部分算法(如 PBKDF2、AES-GCM)虽有实现,但缺少标准的密钥派生参数校验或 AEAD 认证逻辑封装
Web Crypto API 的核心优势
它不是“另一个加密库”,而是浏览器提供的安全子系统接口:
-
密钥抽象化:生成的密钥是
CryptoKey对象,不可序列化为字符串,不能被 console.log 或 JSON.stringify 导出 - 上下文隔离:仅在 HTTPS 页面或 localhost 可用,防止中间人篡改脚本后窃取密钥操作逻辑
-
算法白名单+强制安全参数:例如
AES-GCM要求显式传入 iv 和 tagLength,无法跳过认证步骤;importKey对非安全导入(如 JWK)可设extractable: false - 异步 + Promise 原生支持:所有操作返回 Promise,避免阻塞主线程,适合处理大文件或多次派生
一个安全的 AES-GCM 加解密示例
以下代码演示如何用 Web Crypto API 完成一次端到端加密(含密钥派生和认证):
立即学习“Java免费学习笔记(深入)”;
// 1. 从口令派生加密密钥(PBKDF2 + salt)
async function deriveKey(password, salt) {
const enc = new TextEncoder();
const keyMaterial = await window.crypto.subtle.importKey(
'raw', enc.encode(password), { name: 'PBKDF2' }, false, ['deriveKey']
);
return window.crypto.subtle.deriveKey(
{ name: 'PBKDF2', salt, iterations: 100_000, hash: 'SHA-256' },
keyMaterial,
{ name: 'AES-GCM', length: 256 },
true,
['encrypt', 'decrypt']
);
}
// 2. 加密(自动生成 IV,附带认证标签)
async function encrypt(plainText, password) {
const salt = window.crypto.getRandomValues(new Uint8Array(16));
const iv = window.crypto.getRandomValues(new Uint8Array(12));
const key = await deriveKey(password, salt);
const enc = new TextEncoder();
const cipherData = await window.crypto.subtle.encrypt(
{ name: 'AES-GCM', iv },
key,
enc.encode(plainText)
);
// 返回 salt + iv + ciphertext(base64 方便传输)
return btoa(String.fromCharCode(...salt, ...iv, ...new Uint8Array(cipherData)));
}
// 3. 解密(验证完整性和密文一致性)
async function decrypt(encodedData, password) {
const data = new Uint8Array(atob(encodedData).split('').map(c => c.charCodeAt(0)));
const salt = data.slice(0, 16);
const iv = data.slice(16, 28);
const cipherText = data.slice(28);
const key = await deriveKey(password, salt);
const plainBytes = await window.crypto.subtle.decrypt(
{ name: 'AES-GCM', iv },
key,
cipherText
);
return new TextDecoder().decode(plainBytes);
}
注意:实际使用中需校验 encodedData 长度、IV 是否为 12 字节、salt 是否存在——这些不是 API 强制的,但属于必要安全检查。
什么场景下仍要谨慎?
Web Crypto API 本身安全,但整体安全性取决于你的使用方式:
- 口令强度弱?再好的派生也扛不住暴力破解——应配合前端口令强度提示和后端限速
- 把密钥或口令存在 localStorage?这等于把钥匙挂在门把手上——密钥应只驻留内存,且用完即弃
- 在非安全上下文(HTTP)调用?API 直接抛错——确保部署时启用 HTTPS
- 需要长期存储密钥?考虑
navigator.credentials.create()创建凭据,或与 WebAuthn 结合做用户绑定
Web Crypto API 不是万能钥匙,但它把加密操作从“自己造轮子”变成“调用安全基础设施”。只要理解密钥生命周期、坚持 AEAD 模式、避免明文落地,就能在前端构建真正可信的加解密能力。











