前端加密不能替代HTTPS,因为HTTP页面加载时JS可被篡改、公钥可被替换、明文可被截获,而SubtleCrypto等API依赖HTTPS提供的可信上下文和证书验证,仅当全链路HTTPS有效时密钥生成与加密才安全可靠。
客户端 JavaScript 加密(比如用 SubtleCrypto.encrypt())本身不解决传输通道安全问题。如果页面是 http:// 加载的,攻击者可以篡改 JS 文件、替换公钥、或直接拦截加密前的明文——加密逻辑和密钥都暴露在前端,形同虚设。
真正起作用的是 TLS 层加密:只有整个页面走 https://,浏览器才信任加载的脚本、证书才有效、SubtleCrypto 的密钥生成才不会被降级劫持。
SubtleCrypto API 调用http://localhost:3000,那只是“前端加密 + 半程 HTTPS”,中间段仍是明文加密不是拼接字符串,而是按服务端约定的格式序列化后再加密。常见错误是先 JSON.stringify() 再加密,但没处理字段顺序、空值、特殊字符转义,导致解密后 JSON 解析失败。
推荐做法:构造标准对象 → 按 key 字典序排序 → JSON.stringify() → UTF-8 编码为 Uint8Array → encrypt()。
立即学习“前端免费学习笔记(深入)”;
importKey() 导入,类型设为 "public",格式为 "spki"(RSA 公钥)或 "raw"(AES 共享密钥)ArrayBuffer,需转成 Base64(用 btoa(String.fromCharCode(...)) 或 Buffer.from(...).toString('base64'))再塞进表单字段null、undefined 都可能让后端解析出错加密后的 payload 不能直接当 form 的普通字段提交,因为 enctype="application/x-www-form-urlencoded" 会破坏二进制数据。必须用 fetch() 手动构造请求体。
method: 'POST' 和 headers: {'Content-Type': 'application/json'}
{ "encrypted": "BASE64_STRING", "iv": "BASE64_IV", "timestamp": Date.now() }
FormData 提交加密数据——它默认用 multipart/form-data,后端收不到原始 payloadapplication/x-www-form-urlencoded,则需将加密字段名设为 data,值为 Base64 字符串,并确保 URL 编码正确(encodeURIComponent())Web Crypto 的密钥对象(CryptoKey)无法序列化,也不能跨 iframe 或 service worker 共享。每次页面加载都得重新导入,且密钥生命周期必须严格控制。
localStorage 存私钥——哪怕加密了,也违背密钥隔离原则/api/public-key 接口获取,附带 ETag 避免重复请求navigator.credentials 是否可用,某些隐私模式下 SubtleCrypto 会被禁用