前端API数据RSA非对称加密方法总结

2,827 阅读4分钟

一:对数据加密的概述

一般我们对数据进行加密,主要目的是为了防止信息泄露及篡改。在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传送门