最近接触的项目需要所有数据都走post请求,并且所有数据都要进行加密处理。之前没有相关开发经验,于是就在网上查资料学习,做完之后也对加密流程和加密方式有了基本的认识,最后整理了一个demo出来用于展示成果。
Web 前端密码加密是否有意义?
之前在v2ex看到过大家的讨论,反正各有各的说法,后来在知乎也看到了一样的讨论,其中有个大佬的回复让我印象很深:既然市面上大部分锁都可以在20分钟内撬开,那门上装锁是否还有意义?这个比喻很形象了,如果对数据传输的安全有要求的话,有加密总比没有要强把…
demo演示
preview
github地址
RSA公私钥说明
非对称加密算法需要两个密钥:公开密钥(publickey:简称公钥)和私有密钥(privatekey:简称私钥)。公钥与私钥是一对,如果用公钥对数据进行加密,只有用对应的私钥才能解密。 RSA是最常用的非对称加密算法。
客户端和服务端分别持有自己的私钥,交换公钥。公钥用于参数加密及签名验签,私钥用于参数解密及签名加签。
项目依赖
AES加密及md5散列: crypto.js
RSA加密: jsencrypt
RSA密钥对生成:http://web.chacuo.net/netrsakeypair/
参数说明
数据加密前的原始数据:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| { sequenceNo: this.getGuid(), version: '1.1', timestamp: new Date().getTime(), signature: '', encryptedKey: '', encryptedData: { head: { deviceID: '', ... }, body: {...} } }
|
参数加密
** 生成 encryptedKey 和 encryptedData **
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
| getEncryptedData() { const baseData = { head: { ...this.options.encryptedData.head }, body: { ...this.options.encryptedData.body } } const aesKey = AES.createAesKey(); const iv = AES.createAesIv(); const encryptedData = AES.encryptAES(baseData, aesKey, iv) const objMap = { key: aesKey, iv: iv } const encryptedKey = RSA.publicEncrypt(JSON.stringify(objMap)) return { encryptedKey, encryptedData } }
|
签名
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| sign(signData) { const obj = { encryptedData: MD5(JSON.stringify(this.options.encryptedData)), sequenceNo: this.options.sequenceNo, timestamp: this.options.timestamp, version: this.options.version } const data = signData || obj; const str = RSA.getKeyVal(data); return RSA.privateEncrypt(str) }
|
数据解密
1 2 3 4 5 6 7 8 9 10 11 12 13 14
|
getDecryptedData(key, data) { const decryptKey = RSA.privateDecrypt(key) const objMap = JSON.parse(decryptKey) return AES.decryptAES(data, objMap.key, objMap.iv); }
|
验签
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
|
isPass(signData, signature) { const data = { encryptedData: MD5(this.decrypted), sequenceNo: signData.sequenceNo, timestamp: signData.timestamp, version: signData.version } const responseSign = RSA.getKeyVal(data); const decryptSign = RSA.publicDecrypt(signature); return responseSign === decryptSign }
|
实际开发情况,在响应拦截器下验证签名并通过之后前端就可以正常使用解密后的数据了。
其他
AES加密文档:cryptojs文档
遇到的问题:
现在vue的脚手架的配置文件没有在根目录了,而是直接放在了node_modules包内,刚刚上传demo到主机遇到了文件引入路径不对的问题,需要将node_modules/@vue/cli-service/lib/options.js下的publicPath路径改为’./‘再重新打包。