使用RSA非对称加密+AES对称加密
-
加密类型:
- RSA:是一种非对称加密算法。它使用一对密钥(公钥和私钥),其中公钥可以公开给任何人,用于加密数据;而私钥需要保密,用于解密数据。
- AES:是一种对称加密算法。它使用同一个密钥进行加密和解密操作,这意味着在加密和解密过程中,通讯双方必须共享相同的密钥。这种情况下,密钥的安全传输和管理成为了一个关键问题。
-
性能与效率:
- RSA:RSA的加密和解密速度较慢,不适用于大量数据的直接加密,更适合加密少量数据,如加密会话密钥或者数字签名等。
- AES:AES加密速度快,适合加密大量的数据。
由于AES秘钥放在前端不安全,所以采用如下思路
- 后台生成RSA公钥和私钥,公钥给前端
- 前端生成AES秘钥,并加密data
- 前端使用RSA公钥加密AES秘钥,
- 前端传输给后台加密的data和加密的AES和公钥
- 后台使用对应RSA私钥解密得到AES秘钥,再用AES秘钥解密data
使用 crypto-js 的AES方式对接口参数进行加密
- 安装引入
npm install crypto-js
import CryptoJS from 'crypto-js'; // 使用CryptoJS库进行加密
- 定义加密函数
let key = '5F6B2AK33DASD1235E74C231B47AC8F6' //AES秘钥
// 定义你的加密函数(需要加密的data,AES秘钥)
function encryptData(data,key) {
// 这样写的加密后在线工具可以正常解密,但是后台无法解密
// return CryptoJS.AES.encrypt(JSON.stringify(data), 'sQPoC/1do9BZMkg8I5c09A==').toString();
const _key = CryptoJS.enc.Utf8.parse(key) //将秘钥转换成Utf8字节数组
// const iv = CryptoJS.enc.Utf8.parse(key.substr(0, 16))
//加密
const encrypt = CryptoJS.AES.encrypt(JSON.stringify(data), _key, {
// iv: iv,
mode: CryptoJS.mode.ECB,
padding: CryptoJS.pad.Pkcs7
})
return encrypt.toString()
}
RSA加解密——jsencrypt库
npm install jsencrypt --save
// 或者cdn引入
<script src="https://cdnjs.cloudflare.com/ajax/libs/jsencrypt/3.2.1/jsencrypt.min.js"></script>
- 加密方法
// 需要加密的data,RSA公钥
function rsaEncrypt(data,publicKey) {
var encryptor = new JSEncrypt();
// 假设你已经获取到了后端提供的公钥字符串(key是Base64编码的公钥)
encryptor.setPublicKey(publicKey);
//使用公钥加密
return encryptor.encrypt(data);
}
- 解密方法
// 需要加密的data,RSA私钥
function decrypt(data,privateKey) {
const encryptor = new JSEncrypt()
encryptor.setPrivateKey(privateKey) // 设置私钥
return encryptor.decrypt(data) // 对数据进行解密
}
实际代码逻辑
登录页面路由拦截获取RSA公钥,存储在本地
beforeRouteEnter(to, from, next) {
// 假设有个 API 方法
getRsaPulicKey().then(response => {
console.log(response.data.publicKey)
localStorage.setItem('PublicKey', response.data.publicKey);
next();
}).catch(error => {
// 如果请求失败,可以重定向到错误页面或者其他操作
next('/login');
});
},
在request.js文件进行修改接口参数的修改
- 定义随机AES私钥
/**
* @returns 生成不重复的随机序列号 '60a2cd4faec2474ca6ee43aac3b0bc1d'
* 32位 16进制
*/
function getUUID() {
var d = new Date().getTime();
if (window.performance && typeof window.performance.now === "function") {
d += performance.now(); //use high-precision timer if available
}
var uuid = "xxxxxxxxxxxx4xxxyxxxxxxxxxxxxxxx".replace(/[xy]/g, function (c) {
var r = (d + Math.random() * 16) % 16 | 0;
d = Math.floor(d / 16);
return (c == "x" ? r : (r & 0x3) | 0x8).toString(16);
});
return uuid;
}
// 定义AES加密函数
let AESKey = getUUID()
- 定义AES加密data函数和RSA加密私钥函数
// AES加密数据data
function aesEncrypt(data) {
// 这样写的加密后在线工具可以正常解密,但是后台无法解密
// return CryptoJS.AES.encrypt(JSON.stringify(data), 'sQPoC/1do9BZMkg8I5c09A==').toString();
const _key = CryptoJS.enc.Utf8.parse(AESKey) //将秘钥转换成Utf8字节数组
// const iv = CryptoJS.enc.Utf8.parse(key.substr(0, 16))
//加密
const encrypt = CryptoJS.AES.encrypt(JSON.stringify(data), _key, {
// iv: iv,
mode: CryptoJS.mode.ECB,
padding: CryptoJS.pad.Pkcs7
})
return encrypt.toString()
}
//定义RSA加密函数,,对AES秘钥加密
function rsaEncrypt(publicKey) {
var encryptor = new JSEncrypt();
// 假设你已经获取到了后端提供的公钥字符串(key是Base64编码的公钥)
encryptor.setPublicKey(publicKey);
//使用公钥加密
var plaintext = AESKey;
return encryptor.encrypt(plaintext);
}
- request拦截器判断是登录接口修改其data
// request拦截器
service.interceptors.request.use(config => {
console.log('request11', config, config.data)
if (config.url == "/auth/login") {
let PublicKey = ''
if (!localStorage.getItem("PublicKey")) {
Message({
message: '未获取到公钥',
type: 'error',
})
return
} else {
PublicKey = localStorage.getItem("PublicKey")
}
config.data = {
data: aesEncrypt(config.data), //AES加密后的data
aesKey: rsaEncrypt(PublicKey), //RSA加密后的aes私钥
publicKey: PublicKey //RSA公钥
};
}