前端使用RSA+AES实现请求数据混合加密

明月
• 阅读 360

利用 RSA 来加密传输 AES的密钥,用 AES的密钥 来加密数据 RSA的公钥,私钥由后端提供

创建crpto.js文件
// 引入crypto-js,封装 AES加密,解密方法
import CryptoJS from 'crypto-js'

/**
word :要加密的数据,
key:秘钥(随机生成) 
*/

// AES加密
encryptAES (word, key) {
    let keyAES = CryptoJS.enc.Utf8.parse(key)
    let srcs = CryptoJS.enc.Utf8.parse(word)
    let enc = CryptoJS.AES.encrypt(srcs, key, {mode: CryptoJS.mode.ECB, padding: CryptoJS.pad.Pkcs7}) // 加密模式为ECB,补码方式为PKCS7
    return enc.toString()
},
// AES解密
decryptAES (word, key) {
    let key = CryptoJS.enc.Utf8.parse(key)
    let dec = CryptoJS.AES.decrypt(word, key, {mode: CryptoJS.mode.ECB, padding: CryptoJS.pad.Pkcs7})
    return CryptoJS.enc.Utf8.stringify(dec).toString()
}

后端每次接收到请求,都会将该请求的nonce存入缓存并保持60秒(根据需要设置),时间过后该值将被移除,建议后端采用Redis存储nonce,这样可省去检测和移除nonce的代码。如果后端发现当前请求的nonce存在于已存储的nonce之中,则此请求发生重复 如果只使用nonce我们只能保证该请求60秒内不会重复,但60秒后依然任人宰割,这不是要的结果。所以timestamp将用来限制时间,后端时间戳减去前端发送请求的时间戳,得到的差值为N秒,如果N秒大于60秒则此请求过期,那么则可以保证,60秒内因为nonce相同而被判为请求重放,60秒后因为时间差超过而被判为请求已过期,因此确保了请求不会被重放。

创建RSA.js文件
import CryptoJS from 'crypto-js'
import {JSEncrypt} from 'jsencrypt'

// data:需要加密的请求数据,这里暂时使用假数据
rsaEncrypt(data){
   let data = { name:"张三",telPhone:"15789087655" }
   // 获取时间戳
   let timestamp = new Date().getTime();
   // 获取随机码
   let nonce = randomCode();
   data.timestamp = timestamp;
   data.nonce = nonce;
    // 字段排序(按照首字母)
    const keys = Object.keys(data);
    keys.sort();
    // 拼接字符串
    let signStr = "";
    for(let i=0;i<keys.length;i++){
        const element = keys[i];
        singStr+=`${element}=${data[element]}&`;
    }
    // 拼接key(登录时后端返回的key)
    let key = "SnksifhLAteurhf" // 这里用的假的
    signStr = signStr + 'key='+key;
    // 计算MD5哈希值
    // 拼接的字符串很容易被攻击者伪造签名并篡改数据,所以需要加上登录时返回的唯一的key
    // MD5的目的并不是为了隐藏明文数据,而是让后端进行数据校验 
    // 后端取得请求数据后,将除了sign之外的参数名进行字典排序,
    // sign用一个临时变量存下,然后排好序的参数和前端一样拼接得到字符串。
    // 接下来进行MD5计算即可得到后端获得的签名,此时与请求中
    // 携带的sign比较是否一致则可确定签名是否有效,如果不一致返回签名错误
    const sign = CryptoJS.MD5(signStr).toString();
    data.sign = sign;

    // RSA公钥(登录时后端返回的)(这里用的假的,真实的公钥很长------)
    let publicKey = "Misfsdfsfffsfsdfsfss"
    // 随机生成AES秘钥(长度自定义)
    let aesRandomStr = randomCode();
    // 使用AES秘钥加密数据
    let datas = crpto.encryptAES(JSON.Stringfy(data),aesRandomStr)
    // rsa加密AES秘钥
    const encrypts = new JSEncrypt()
    // 设置公钥
    encrypts.setPublicKey(publicKey)
    // 加密AES秘钥
    let encryptedKey = encrypts.encrypt(aesRandomStr)
    let json={
        "encryptedData":data,
        "encryptedKey":encryptedKey
    }
    return json
}

    // 生成随机码
    randomCode(){
        let possible="QWERTYUIOPLKMJNHBGVFCDXSZAqwertyuiolpkmjnhbgvfcdxsza1234567890"
        let randomCode = '';
        for(let i=0;i<16;i++){
        randomCode+=possible.charAt(Math.floor(Math.random()*possible.length))
    }

    // 解密 
    // 解密是后端进行的,这里的解密方法只是为了前端自测,确保前端加密的数据-自己能解开
    rsaDecryptData(result){
        const decrypted = new JSEncrypt()
        let privateKey = "hasahdaiasuivuivb";
        decrypted.setPrivateKey(privateKey)
        let aesKey = decrypted.decrypt(result.encryptedKey)
        let dataRes = crpto.decryptAES(result.encryptedData,aesKey)
        return JSON.Parse(dataRes)
    }
}
点赞
收藏
评论区
推荐文章
Wesley13 Wesley13
3年前
java将前端的json数组字符串转换为列表
记录下在前端通过ajax提交了一个json数组的字符串,在后端如何转换为列表。前端数据转化与请求varcontracts{id:'1',name:'yanggb合同1'},{id:'2',name:'yanggb合同2'},{id:'3',name:'yang
Easter79 Easter79
3年前
springboot2之优雅处理返回值
前言最近项目组有个老项目要进行前后端分离改造,应前端同学的要求,其后端提供的返回值格式需形如{"status":0,"message":"success","data":{}}方便前端数据处理。要实现前端同学这个需求,其实也挺简单的,
Stella981 Stella981
3年前
AssemblyScript 入门指南[每日前端夜话0xEB]
每日前端夜话0xEB每日前端夜话,陪你聊前端。每天晚上18:00准时推送。正文共:2459 字预计阅读时间:10分钟作者:DannyGuo翻译:疯狂的技术宅来源:logrocket!(https://oscimg.oschina.net/oscnet/b880277c594152a503
Stella981 Stella981
3年前
Node.js 12中的ES模块[每日前端夜话0x9E]
每日前端夜话0x9E每日前端夜话,陪你聊前端。每天晚上18:00准时推送。正文共:2552字预计阅读时间:10 分钟作者:BrianDeSousa翻译:疯狂的技术宅来源:logrocket!(https://oscimg.oschina.net/oscnet/2ccaf94cecd3
Stella981 Stella981
3年前
API 接口设计中 Token 类型的分类与设计
在实际的网站设计中我们经常会遇到用户数据的验证和加密的问题,如果实现单点,如果保证数据准确,如何放着重放,如何防止CSRF等等其中,在所有的服务设计中,都不可避免的涉及到Token的设计。目前,基于Token的生成方,我们把Token生成分为两种类型。1、基于用户/网站,可见的加密请求方式2、基于服务器间通讯的不可见加密请求方式(API To
Easter79 Easter79
3年前
SpringMVC中url映射到Controller
SpringMVC也是一种基于请求驱动的WEB框架,并且使用了前端控制器的设计模式。前端控制器就是DispatcherServlet控制器,只要满足web.xml文件中的【urlpattern】的规则,这个请求就会交给这个前端控制器(DispatcherServlet),然而前端控制器在收到请求后自己不进行任何处理,根据相应的【URL的映射规则】委托给其他
可莉 可莉
3年前
12306 抢票系列之只要搞定RAIL_DEVICEID的来源,从此抢票不再掉线(上)
郑重声明:本文仅供学习使用,禁止用于非法用途,否则后果自负,如有侵权,烦请告知删除,谢谢合作!开篇明义本文针对自主开发的抢票脚本在抢票过程中常常遇到的请求无效等问题,简单分析了12306网站的前端加密算法,更准确的说,是探究RAIL_DEVICEID的生成过程.因为该cookie值是抢票请求
Stella981 Stella981
3年前
12306 抢票系列之只要搞定RAIL_DEVICEID的来源,从此抢票不再掉线(上)
郑重声明:本文仅供学习使用,禁止用于非法用途,否则后果自负,如有侵权,烦请告知删除,谢谢合作!开篇明义本文针对自主开发的抢票脚本在抢票过程中常常遇到的请求无效等问题,简单分析了12306网站的前端加密算法,更准确的说,是探究RAIL_DEVICEID的生成过程.因为该cookie值是抢票请求
Wesley13 Wesley13
3年前
2、SpringMVC的执行流程
2.1图示!(https://oscimg.oschina.net/oscnet/upa84a47f9ba12dc7770d5cf6a8ddb12e0ff2.png)2.2执行流程1.用户发送请求至前端控制器DispatcherServlet。2.前端控制器DispatcherServlet收到请求后调用处理器映射
Wesley13 Wesley13
3年前
MySQL部分从库上面因为大量的临时表tmp_table造成慢查询
背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_
明月
明月
Lv1
纷纷万事,直道而行!
文章
5
粉丝
3
获赞
12