前端怎么安全地交换加密密钥?
我在做一个需要前端加密用户数据的功能,但卡在密钥交换这一步了。后端给的 API 返回一个公钥,我用 crypto.subtle.encrypt() 加密数据发过去,但每次刷新页面密钥就变了,没法解密之前的数据。
我看别人用 ECDH 做密钥协商,但在浏览器里试了下根本拿不到对方私钥啊?是不是理解错了?现在临时方案是把密钥存在 localStorage,但这明显不安全……
这是我现在生成密钥对的代码:
const keyPair = await crypto.subtle.generateKey(
{ name: 'ECDH', namedCurve: 'P-256' },
true,
['deriveKey']
);
const publicKey = await crypto.subtle.exportKey('spki', keyPair.publicKey);
问题是:前端和后端之间到底该怎么安全地协商出一个共享密钥,还能保证用户换设备也能解密历史数据?
简单说:每次刷新生成新密钥对没问题,但你得把私钥存下来(存 localStorage 就行,用用户密码再加密一层更稳妥)。然后用你的私钥+后端公钥 deriveKey 得到共享密钥,加密数据发过去。后端用它的私钥+你的公钥也能 derive 出同一个共享密钥。
跨设备解密的问题:把你前端生成的私钥用用户密码加密后存到后端数据库,换设备时用户输入密码就能恢复私钥,然后继续跟后端协商。