前端用RSA加密时,私钥怎么安全传给后端不被窃取?
我在用RSA加密用户密码时遇到个难题,前端生成密钥对后,必须把私钥发给后端解密,但这样私钥不就暴露在请求里了吗?比如这段代码:
const forge = require('node-forge');
const keypair = forge.pki.rsa.generateKeyPair();
const privateKey = keypair.privateKey;
// 尝试加密密码
const encrypted = privateKey.encrypt('userPassword');
// 发现需要把私钥传给后端
fetch('/api/submit', {
method: 'POST',
body: JSON.stringify({ privateKey: privateKey.toString(), encrypted })
});
测试时发现这样传输私钥太危险了,但如果不传私钥,后端又无法解密数据。我试过用AES包裹RSA,但前端没有安全保存私钥的办法,感觉陷入死循环了…
你想想,如果私钥得从浏览器传出去,那它早就暴露在中间人手里了,连加密的意义都没了。RSA在前端用,一定是公钥加密、私钥解密,而私钥必须死死攥在后端,从来不会也不应该出现在前端。
正确做法是:
后端先生成RSA密钥对,把公钥通过接口(比如 /api/rsa/public-key)返回给前端,前端拿到公钥后用来加密密码,再把加密后的密文发回后端,后端用自己的私钥解密。全程私钥不离后端,公钥随便传。
代码大概长这样:
后端(以 Node.js 为例)先生成一次密钥对,存在内存或配置里(别存数据库里明文存啊):
前端拿到公钥参数后,用 forge 构造公钥对象来加密:
注意几点:
- 公钥本身是明文传输没问题,它本来就是公开的
- 前端每次请求前拿一次公钥也可以,但更常见的是后端统一下发一次,前端缓存
- 如果担心公钥被替换(比如中间人篡改),那得上 HTTPS,别想在纯 HTTP 上靠自己实现“更安全”
你原来的思路错在把“密钥生成”和“密钥分发”混在一起了——RSA 的密钥生成必须在解密方(后端)做,加密方(前端)只配用公钥。这就像你寄信,信封上的地址是公开的(公钥),但只有收信人手里的钥匙能开锁(私钥),你不可能把钥匙贴在信封上寄出去。
再补充一句:真要高安全场景,别自己造轮子,直接上 TLS 握手那一套(也就是 HTTPS),RSA 只是它底层用的工具之一。
正确流程应该是:
后端提前生成好RSA密钥对,保存私钥到文件/环境变量
前端登录时请求公钥
前端用公钥加密密码
后端收到加密数据后用私钥解密
补充两点注意事项:
公钥加密的数据只能私钥解密,中间就算被截获也没用
每次加密应该生成随机密钥,用公钥加密这个密钥,再用AES加密数据
给个简单示例:
后端用crypto模块处理解密: