前端对密码加密以及后端解密的一个尝试
前言:
前端对敏感信息进行加密已经是一个屡见不鲜的事情了,但是现在很对B端项目还在进行明文传输密码等敏感信息,这是一个很不安全的行为。
加密方式
- 对称加密
- 密钥:同一个密钥。加密方和解密方必须事先共享同一个密钥,并且保证这个密钥的安全
- 加密速度:通常更快,因为它使用较简单的算法来处理大量数据
- 安全性:虽然加密算法难以破解,但是密钥可能会泄露
- 场景:数据库,文件加密
- 常用加密算法:
AES,DES,SM1
- 非对称加密
- 密钥:公钥和私钥。使用公钥加密 ,私钥解密
- 加密速度:相对较慢
- 安全性:更安全,只要保存好私钥,即使有了公钥也无法解密
- 场景:密码,数字签名
- 常见加密算法:
RSA,ECCSM2
本篇主要介绍RSA加密在前(vue、react)后端(node)的一个过程
接下来看下具体的一个代码
const crypto = require('crypto')
const fs = require('fs')
const generateKeyPem = () => {
// 生成 RSA 密钥对
crypto.generateKeyPair(
'rsa',
{
modulusLength: 2048, // 密钥长度
publicKeyEncoding: {
type: 'pkcs1',
format: 'pem', // 输出格式
},
privateKeyEncoding: {
type: 'pkcs1',
format: 'pem', // 输出格式
},
},
(err, publicKey, privateKey) => {
if (err) {
console.error('生成密钥对时发生错误:', err)
return
}
// 将公钥写入文件
fs.writeFileSync('public_key.pem', publicKey)
// 将私钥写入文件
fs.writeFileSync('private_key.pem', privateKey)
},
)
}
接下来我们看下前端加密和后端解密的一个过程
import JSEncrypt from "jsencrypt";
const encrypt = new JSEncrypt();
encrypt.setPublicKey(publicKey);
const encryptedPassword = encrypt.encrypt(password);
后端解密
const privateKey = fs.readFileSync('private_key.pem', 'utf8')
const decryptedPassword = crypto.privateDecrypt(
{
key: privateKey,
padding: crypto.constants.RSA_PKCS1_PADDING,
},
Buffer.from(encryptedPassword, 'base64'),
)
const newPassword = decryptedPassword.toString()
以上的代码在node16.20版本是可以运行的,但是在node20+的版本会报错,报错这个错误
RSA_PKCS1_PADDING is no longer supported for private decryption, this can be reverted with --security-revert=CVE-2023-46809
这个消息是与OpenSSL相关的更新。OpenSSL在新的版本中由于安全原因已经停止支持RSA_PKCS1_PADDING用于私钥解密操作,这是因为存在安全漏洞(CVE-2023-46809)
为了兼容我们只能修改我们的一个加密和解密方式
这个经过查询,得到一个结果说是我们可以使用OAEP 的方式对密钥加密进行一个填充
经过修改,前后端加密解密的过程为
import forge from "node-forge";
const publicKeyPem = forge.pki.publicKeyFromPem(publicKey);
// 使用OAEP填充进行加密
const encrypted = publicKeyPem.encrypt(password, "RSA-OAEP", {
md: forge.md.sha256.create(), // 使用SHA-256作为哈希函数
mgf1: {
md: forge.md.sha256.create() // 使用SHA-256作为MGF1的哈希函数
}
});
// 将加密数据转换为Base64格式,以便传输
const encryptedPassword = forge.util.encode64(encrypted);
const privateKey = fs.readFileSync('private_key.pem', 'utf8')
const decryptedPassword = crypto.privateDecrypt(
{
key: privateKey,
padding: crypto.constants.RSA_PKCS1_OAEP_PADDING,
oaepHash: 'sha256',
},
Buffer.from(encryptedPassword, 'base64'),
)
const newPassword = decryptedPassword.toString('utf8')