使用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加密后的dataaesKey: rsaEncrypt(PublicKey), //RSA加密后的aes私钥publicKey: PublicKey //RSA公钥};}