一:对数据加密的概述
一般我们对数据进行加密,主要目的是为了防止信息泄露及篡改。在http协议下,数据是明文传输的,如果用户的信息及相关的资料,一旦被窃取,会给用户带来极大的安全隐患。另一方面在非加密的传输过程中,攻击者可更改数据或插入恶意的代码等。前端加密的意义:在数据发送前将数据进行“哈希”或使用“公钥"加密,输出的则是加密后的数据,不再是明文。
- (AES)对称加密:加密密钥和解密密钥相同。
- (RSA)非对称加密:加密密钥和解密密钥不相同。
注意:非对称加密的安全性更高,但加密速度较慢。一般我们在项目中采用的是 ”结合对称和非对称加密,数据加密采用AES,而把AES的加密秘钥用RSA加密,这样兼顾速度及安全性“。
二:常见前端加密方式
1:MD5(某种角度来说,只是一种编码方式)
一种被广泛使用的密码散列函数,可以产生出一个128位(16字节)的散列值(hash value),用于确保信息传输完整一致。特点是加密后的结果长度一致且不可逆。
2:Base64(某种角度来说,只是一种编码方式)
Base64是网络上最常见的用于传输8Bit字节码的编码方式之一,Base64就是一种基于64个可打印字符来表示二进制数据的方法。Base64编码是从二进制到字符的过程,可用于在HTTP环境下传递较长的标识信息。采用Base64编码具有不可读性,需要解码后才能阅读。
3:AES
高级加密标准(AES),这个标准用来替代原先的DES,已经被多方分析且广为全世界所使用,成为对称密钥加密中最流行的算法之一。
4:RSA
RSA公开密钥密码体制是一种使用不同的加密密钥与解密密钥,“由已知加密密钥推导出解密密钥在计算上是不可行的”密码体制。RSA是被研究得最广泛的公钥算法,经历了各种攻击的考验,普遍认为是目前最优秀的公钥方案之一。
三:接口数据RSA加密流程
注:每个公司的加密流程不一样 (以下流程是我司的加密流程)
- 对前端API请求数据进行字典排序 最后转JSON字符输出
- 对该字符串用AES对称加密,输出密文
- 输出被RSA公钥加密过的AES密钥字符串
- 通过时间戳,随机字符串拼接而成的签名
- 对该签名进行AES加密后输出
//返回的数据
resultData(val){
let newObj = {};
let randomVal = this.randomString(16); //16位随机字符串AES密钥
newObj.timestamp = this.timesTamp(); //时间戳
newObj.nonce = this.randomString(16); //随机字符串
newObj.encrypt = this.aesEncrypt(this.objSort(val),randomVal); //数据字典排序,加密后的密文
newObj.echokey = this.rsaEncrypt(randomVal); //被RSA公钥加密过的AES密钥字符串
newObj.signature = this.aesEncrypt(newObj.timestamp + newObj.nonce + randomVal,randomVal);
return JSON.stringify(newObj);
},
四:WEB端
- WEB端采用的是node-rsa进行数据加密。支持node环境及浏览器环境,支持超长字符加密。github传送门
npm i node-rsa --save--dev
- RSA非对称加密 使用方法 (上代码)
import NodeRSA from 'node-rsa';
//非对称加密方法 文本内容长度无限制
rsaEncrypt(data){
// 公钥
const PUBLIC_KEY = 'xxxxxxxxxxxxx';
let clientKey = new NodeRSA(`-----BEGIN PUBLIC KEY-----${PUBLIC_KEY}-----END PUBLIC KEY-----`);
clientKey.setOptions({encryptionScheme: 'pkcs1'}); //指定RSA加密协议,pkcs1 或 pkcs1_oaep,默认pkcs1_oaep
const result = clientKey.encrypt(data, 'base64'); // 指定输出编码类型为base64
return result;
},
- 再附上AES对称加密 使用方法
import CryptoJS from 'crypto-js';
//对称加密方法 (注:需先安装crypto-js)
aesEncrypt(data){
const key = CryptoJS.enc.Utf8.parse(设置的是AES密钥);
const ivs = CryptoJS.enc.Utf8.parse('xxxx设置的IVS值xxxx');
const encrypted = CryptoJS.AES.encrypt(data, key, {
iv: ivs,
mode: CryptoJS.mode.CBC,
padding: CryptoJS.pad.Pkcs7
});
return encrypted.toString()
},
注:网上有很多文章都是使用jsencrypt.js进行RSA加密,jsencrypt对文本内容是有要求的,长文本会出现报错提示”Message too long for RSA“。有文章说引用 encryptlong.js可解决这个问题。本人尝试过,引用encryptlong后没有什么卵用,引用后对数据进行加密后直接返回false (需要修改源代码),当时心里一万个草泥马在狂奔。最后直接弃用了jsencrypt,采用 node-rsa 进行RSA 加密,轻松解决问题。希望有需要用到RSA加密的码农门少走弯路。 微信小程序端无法使用 node-rsa 插件,构建时会报错,有大神已经进行二次封装过,在此附上 wxmp-rsa传送门