博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
前端加解密方案探讨
阅读量:4918 次
发布时间:2019-06-11

本文共 4525 字,大约阅读时间需要 15 分钟。

最近在做一个node项目,需要对前端传递给node端的敏感数据进行加密,并在node端对该加密数据进行解密;因为在做node项目之前,与后端配合开发过类似的需求,即前端加密后端解密;所以就尝试采用RSA非对称加密算法来实现。由于第一次采用RSA来完成加解密的整个过程,遇到了不少坑;不过由于种种原因,最后采用了AES的加密方式;下面就来说说前端加解密实现方案。

RSA加解密算法

实现思路

当然首先想到采用的加解密算法就是,其关键在于算法的公钥/秘钥。其主要用法:

  • 算法生成一份公钥和私钥,其中公钥是公开的,所有人都可以知道,私钥是保密的
  • 用公钥解密,要用私钥解密

于是,基于RSA算法来实现加解密,找到了对应的浏览器端库和node端的库来实现具体的功能。

具体实现思路:

使用jsencrypt在前端实现用公玥加密,使用node-rsa在node端用私钥解密。

遇到的坑

由于采用的是RSA算法,所以需要前后端约定具体的公钥和私钥。怎么生存公钥私钥呢?

于是根据jsencrypt库的介绍,使用方式来生成对应的公钥和私钥。于是生成的公钥和私钥大概是如下样子:

// 私钥-----BEGIN RSA PRIVATE KEY-----MIICXQIBAAKBgQDlOJu6TyygqxfWT7eLtGDwajtNFOb9I5XRb6khyfD1Yt3YiCgQWMNW649887VGJiGr/L5i2osbl8C9+WJTeucF+S76xFxdU6jE0NQ+Z+zEdhUTooNRaY5nZiu5PgDB0ED/ZKBUSLKL7eibMxZtMlUDHjm4gwQco1KRMDSmXSMkDwIDAQABAoGAfY9LpnuWK5Bs50UVep5c93SJdUi82u7yMx4iHFMc/Z2hfenfYEzu+57fI4fvxTQ//5DbzRR/XKb8ulNv6+CHyPF31xk7YOBfkGI8qjLoq06V+FyBfDSwL8KbLyeHm7KUZnLNQbk8yGLzB3iYKkRHlmUanQGaNMIJziWOkN+N9dECQQD0ONYRNZeuM8zd8XJTSdcIX4a3gy3GGCJxOzv16XHxD03GW6UNLmfPwenKu+cdrQeaqEixrCejXdAFz/7+BSMpAkEA8EaSOeP5Xr3ZrbiKzi6TGMwHMvC7HdJxaBJbVRfApFrE0/mPwmP5rN7QwjrMY+0+AbXcm8mRQyQ1+IGEembsdwJBAN6az8Rv7QnD/YBvi52POIlRSSIMV7SwWvSK4WSMnGb1ZBbhgdg57DXaspcwHsFV7hByQ5BvMtIduHcT14ECfcECQATeaTgjFnqE/lQ22Rk0eGaYO80cc643BXVGafNfd9fcvwBMnk0iGX0XRsOozVt5AzilpsLBYuApa66NcVHJpCECQQDTjI2AQhFc1yRnCU/YgDnSpJVm1nASoRUnU8Jfm3Ozuku7JUXcVpt08DFSceCEX9unCuMcT72rAQlLpdZir876-----END RSA PRIVATE KEY-----
// 公钥-----BEGIN PUBLIC KEY-----MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDlOJu6TyygqxfWT7eLtGDwajtNFOb9I5XRb6khyfD1Yt3YiCgQWMNW649887VGJiGr/L5i2osbl8C9+WJTeucF+S76xFxdU6jE0NQ+Z+zEdhUTooNRaY5nZiu5PgDB0ED/ZKBUSLKL7eibMxZtMlUDHjm4gwQco1KRMDSmXSMkDwIDAQAB-----END PUBLIC KEY-----

于是,使用生成的公钥,前端使用jsencrypt提供的加密api来对敏感数据加密

var publickey = `-----BEGIN PUBLIC KEY----- xxxxxx  -----END PUBLIC KEY-----`;var encrypt = new JSEncrypt();encrypt.setPublicKey(publickey);var encryptdata = encrypt.encrypt(data);

node端使用node-rsa来完成解密:

const privatekey = `-----BEGIN RSA PRIVATE KEY----- xxxx  -----END RSA PRIVATE KEY-----`const rsa = new NodeRSA(privatekey, 'pkcs8-private-pem', {encryptionScheme: 'pkcs1'});const decryptdata = rsa.decrypt(data, 'utf8');

执行到这里,node-rsa一直报下面的错误:

Error: Error during decryption (probably incorrect key). Original error: Error: Incorrect data or key

意思就是对应的解密私钥不正确,查看node-rsa有关公钥私钥,他是有规定的,具体如下:

408483-20181223155912689-2019550777.png

可以看出,node-rsa的公钥私钥的起始字符串有以下两种:

  • pkcs1: 公钥(-----BEGIN RSA PUBLIC KEY-----)和私钥(-----BEGIN RSA PRIVATE KEY-----)

  • pkcs8: 公钥(-----BEGIN PUBLIC KEY-----) 和 私钥 (-----BEGIN PRIVATE KEY-----)

不管node-rsa规定的那种私钥scheme,都与我们之前使用openssl生成的私钥字符串的开始结束字符不同,导致node-rsa认不出对应的私钥。

那么,我们是否可以对openssl生成的私钥的起始字符串按照node-rsa进行修改呢,我们简单试一下,结果产生如下错误:

InvalidAsn1Error: Expected 0x30: got 0x2

所以,既然不能按照openssl生成的公钥私钥方式,那么能否有其他方式来生成呢?通过google发现,可以通过node-rsa的相关api来生成对应的公钥私钥,并且jsencrypt库也可以通过其生成的公钥来解密。node-rsa对应生成公钥私钥如下:

//1.创建RSA对象,并指定 秘钥长度  var key = new NodeRSA({ b: 512 });  key.setOptions({ encryptionScheme: 'pkcs1' });//指定加密格式  //2.生成 公钥私钥,使用 pkcs8标准,pem格式  var publicPem = key.exportKey('pkcs8-public-pem');//制定输出格式  var privatePem = key.exportKey('pkcs8-private-pem');  console.log(pkcsType+'公钥:\n',publicPem);  console.log(pkcsType+'私钥:\n', privatePem);

这样,通过生成的公钥,前端使用jsencrypt库来加密,node端使用node-rsa根据私钥来解密,解决了之前遇到问题。

AES加密算法

在使用RSA加密算法前,使用过前端加密库来完成加解密,因为:

  • 它算是比较成熟且github star数也比较多,使用起来比较放心。

  • crypto-js也提供了多种加密算法,唯独不包含RSA加密算法。

  • 该库是前后端通用的库,避免引入多个库

基于此原因,选用了crypto-js提供的AES加密算法来完成需求。

具体的实现方式如下

浏览器端加密

具体代码如下:

import CryptoJS from 'crypto-js';const AES_KEY = "qq3217834abcdefg"; //16位const AES_IV = "1234567890123456";  //16位function aes_encrypt(plainText) {    var encrypted = CryptoJS.AES.encrypt(plainText, CryptoJS.enc.Utf8.parse(AES_KEY), {iv:  CryptoJS.enc.Utf8.parse(AES_IV)});    return CryptoJS.enc.Base64.stringify(encrypted.ciphertext);}data = 'my message';encrypt_data = aes_encrypt(data);console.log(encrypt_data);

node端使用浏览器端同样的keyiv来解密

对应的node端代码如下:

function aes_decrypt(ciphertext) {    var decrypted = CryptoJS.AES.decrypt(ciphertext, CryptoJS.enc.Utf8.parse(AES_KEY), {iv: CryptoJS.enc.Utf8.parse(AES_IV)});    return decrypted.toString(CryptoJS.enc.Utf8);}const encrypt_data = ctx.cookie('data');cibst decrypt_data = aes_decrypt(encrypt_data);console.log(decrypt_data);

至此,前后端加解密就大功告成了。

前端加密算法的安全性

上面两种方式都能实现前后端的加密解密,就其安全性而言存在差别,具体可以参考如下对比表格:

加密算法 实现方式 安全性
RSA 前后端约定统一的公钥私钥,前端用暴露的公钥加密,私钥存在后server端 私钥存在server端,即使暴露公钥;加密是安全的
AES 前端后端都使用同样的key(或者还有iv)来进行加解密,key同时暴露在前后端 由于后端使用同样的key来解密,由于前端暴露了key,加密不安全

对于AES这种将加密key暴露在前端,不够安全;但是前端加密是防不了小人的,如果真要防,可以将加密算法的js文件进行压缩加密,不断更新的手段来使js文件难以获取,让攻击者难以获取加密算法来防止。

参考文献

1、

2、
3、
4、

转载于:https://www.cnblogs.com/wonyun/p/10164364.html

你可能感兴趣的文章
常用vim命令
查看>>
Day18 高阶函数
查看>>
Tomcat工作原理
查看>>
我的Python分析成长之路7
查看>>
Window对象 setInterval()方法应用
查看>>
CSS样式-文字在一行内显示不换行,超出部分用省略号(white-space、overflow、text-overflow、word-wrap、word-break)...
查看>>
Linux下安装jdk
查看>>
python 中关于descriptor的一些知识问题
查看>>
Golang的方法传递值应该注意的地方
查看>>
XMIND 是一款非常实用的商业思维导图(Mindmap)软件
查看>>
Intent 匹配规则
查看>>
windows 安装nvm步骤(shi'yongnvm-windows管理node版本):
查看>>
JdbcUtils
查看>>
「SCOI2014」方伯伯的玉米田 解题报告
查看>>
eclipse中web项目部署到本地tomcat中,但是在本地的tomcat的webapp下找不到发布的项目...
查看>>
使用PHP连接、操纵Memcached的原理和教程
查看>>
在网页中运用统计Web Service接口
查看>>
python入门(八):连接mysql和STMP
查看>>
将图片地址转为blob格式的例子
查看>>
Entity Framework In Action(1)——数据环境准备
查看>>