前端加密之接口RSA加密(h5+小程序,支持超长内容、中文字符)

一、前端加密概述
加密目的:
1、防止信息泄露(防止用户登录账号、密码等)
2、防止数据篡改(防止篡改数据后模拟请求等)

设计原则:
1、加密方式安全可靠
2、开发成本可接受
3、易于调试测试

加密范围:
1、业务相关api接口请求
2、排除图片和文件上传

二、常见的加密方式
1、Base64
Base64是网络上最常见的用于传输8Bit字节码的编码方式之一,Base64就是一种基于64个可打印字符来表示二进制数据的方法。Base64编码是从二进制到字符的过程,可用于在HTTP环境下传递较长的标识信息。采用Base64编码具有不可读性,需要解码后才能阅读。

2、MD5
一种被广泛使用的密码散列函数,可以产生出一个128位(16字节)的散列值(hash value),用于确保信息传输完整一致。特点是加密后的结果长度一致且不可逆。

3、AES
密码学中的高级加密标准(AES),这个标准用来替代原先的DES,已经被多方分析且广为全世界所使用,成为对称密钥加密中最流行的算法之一。

4、RSA
RSA公开密钥密码体制是一种使用不同的加密密钥与解密密钥,“由已知加密密钥推导出解密密钥在计算上是不可行的”密码体制。RSA是被研究得最广泛的公钥算法,经历了各种攻击的考验,普遍认为是目前最优秀的公钥方案之一。

对称加密:加密密钥和解密密钥相同。
非对称加密:加密密钥和解密密钥不相同。
某种角度来说,Base64和MD5不算是加密方式,只是一种编码方式,在特定的场景下发挥作用。
对于加密来说,目前对称加密使用AES居多,非对称加密使用RSA居多。
相对于对称加密来说,非对称加密的安全性更高,但加密速度较慢。
所以,一种推荐的方案是结合对称和非对称加密,数据加密采用AES,而把AES的加密秘钥用RSA加密,这样兼顾速度及安全性。
然并卵,我司采用的仍然是纯RSA加密,本文主要讲的就是纯RSA加密方式。


三、接口RSA加密
加密流程:

前端api请求数据转json字符串
对该字符串用RSA公钥加密
生成base64格式字符串
后端接收用RSA私钥解密
注意点:RSA 算法规定:待加密的字节数不能超过密钥的长度值除以 8 再减去 11,加密后得到密文的字节数,是密钥的长度值除以 8。
所以,如果要加密较长的字符串,需要采用分段加密的方式。


四、h5端
h5端的RSA加密使用了node-rsa插件github地址:https://github.com/Siwen666/node-rsa,支持node环境及浏览器环境,支持超长字符加密。
安装插件依赖:
npm i node-rsa -S
1
使用方式

扫描二维码关注公众号,回复: 14400889 查看本文章
import NodeRSA from 'node-rsa'

// 定义待加密的字符串(换成你的接口请求数据转换后的json字符串)
const str = '{"name":"neo"}'
// 定义公钥(换成你自己的公钥)
const publicKey = `
  -----BEGIN PUBLIC KEY-----
  SSS0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCZYGuVQdX6RSb5TUN8xfIHjw+J
  SFSDcDzLPp/Ug/fmmt++guuDI4wl72G9Z9df+0BKgRwknOmuqO9FkM1rlEdUOx6
  HFolje4A/aEp6/HFUcpoQF6sQkGQ3Yvx4RwMYtOgOotucB2TRSd2NuQNpEivGa
  NFW7jihJTegg3D6wIDAQAB
  -----END PUBLIC KEY-----
`

const myEncrypt = new NodeRSA(publicKey)
myEncrypt.setOptions({ encryptionScheme: 'pkcs1' }) // 指定RSA加密协议,pkcs1 或 pkcs1_oaep,默认pkcs1_oaep
const cryptStr = myEncrypt.encrypt(str, 'base64') // 指定输出编码类型为base64

console.log('加密后的结果:', cryptStr)



五、微信小程序端
上述h5端用的node-rsa插件在微信小程序里无法使用(构建npm后报错)
其他各类插件也试了好几个,要么不支持超长加密,要么体积太大容易导致小程序主包体积超限(2Mb限制)
最终使用了基于插件jsencrypt二次修改封装,已发布到npm上,安装及使用方式参考文档:wxmp-rsa(欢迎star)。
注意:这个加密工具有个问题就是偶现的会有加密出错的情况(出错时解密出来的字符串后半部分都是重复的),经反复测试发现是插件jsencrypt本身的bug,目前还不清楚bug产生的原因,出现概率1%左右。
我的解决方法就是判断加密前和解密后的字符串是否一致,不一致就重新加密一次,最多重复十次(目前遇到的都是出错后重新加密一次就正常了),这部分我已经做了封装,只要设置了私钥就能生效。
那么问题来了,解密需要私钥,有了私钥才能处理偶现加密出错的问题,那么公钥和私钥都存在前端了,确实是不安全,但是有加密总比没有好,而且小程序里的前端源码也不容易趴下来,实在不行你可以对密钥字符串做个混淆处理。
如果有更好的解决方法,欢迎分享。


六、提示
为了方便调试及测试,建议在测试环境关闭加密功能,在预发环境和线上环境再开启。
要进一步提升安全性,可视情况考虑以下方式:
1、密钥不存储在前端,而是从后端接口获取。
2、后端可以对密钥使用混淆或简单加密后再传给前端。
3、由后端获取密钥时,后端可以定期更改密钥。
4、不同的端分别使用不同的密钥处理,例如android、ios、h5、小程序等前端使用不同的密钥。
————————————————

原文链接:https://blog.csdn.net/u010059669/article/details/109067975

猜你喜欢

转载自blog.csdn.net/weixin_42602900/article/details/115393339#comments_22225655