目录

前言

功能设计

客户端的功能点(client)

服务端的功能点(server)

功能实现

工具函数

client.js(客户端)

server.js(服务端)

实现效果

写在最后


前言

在网络通信中,如果数据包是明文传输,并且包含敏感信息,那么就很容易被抓包窃取,因此加密手段也成了开发者耳熟能详的知识技能;常见的加密方法有对称加密和非对称加密。对称加密使用同一个密钥进行加密和解密,而非对称加密使用公钥和私钥分别进行加密和解密。

另一个需要知识点是防重放措施,防重放攻击是指攻击者会拦截请求并重新发送,从而导致重复处理。常见的防重放攻击方法有使用令牌桶算法和使用 Nonce 值(随机数)。

那么这二者为何会结合在一起呢?

原因是我之前做的零食商贩的案例暴露出来的问题,虽然接口做了加密处理,使用者不容易轻易知道数据包的内容,但是如果复制一个接口再次发起请求还是可以成功,因为接口没有做类似文件阅后即焚的功能,所以做个分享。

功能设计

因为客户端和服务端都在node中实现,所以通信暂时摒弃请求的方式,使用消息中心模拟前后端请求的操作

客户端的功能点(client)

  • 通过invoke发送请求
  • 创建Nonce随机值
  • crypto.aes加密参数

服务端的功能点(server)

  • 通过watch接收请求
  • Nonce查重
  • crypto.aes解密参数
  • 通过bcryptjs哈希处理对比密码是否正确
  • jsonwebtoken创建及校验token

功能实现

工具函数

helper.bcrypt.js(针对密码进行哈希盐加密)

const bcryptjs = require("bcryptjs");
// 哈希盐加密
exports.createBcrypt = (password, salt = bcryptjs.genSaltSync(10)) => {return bcryptjs.hashSync(password, salt);
};
// 校验密码
exports.checkBcrypt = (_password, _hash) => {return bcryptjs.compareSync(_password, _hash);
};

helper.random.js(生成随机数+时间戳的字符串)

const { randomNum } = require("utils-lib-js");
// 生成Nonce随机数
exports.createRandom = () => {const date = new Date().getTime();const start = 0x000000;const end = 0xffffff;return randomNum(start, end) + date;
};

helper.jwt.js(JSONwebtoken加解密)

const { sign, verify } = require("jsonwebtoken");
const { defer } = require("utils-lib-js");
const { TokenKey } = require("../config");
// 新建令牌
exports.createToken = ({payload = {},tokenKey = TokenKey,expiresIn = "1d",...others
}) => {return sign({ payload }, tokenKey, {expiresIn,...others,});
};
// 校验令牌
exports.checkToken = ({ token, tokenKey = TokenKey, options }) => {const { reject, resolve, promise } = defer();verify(token, tokenKey, options, (err, decoded) => {if (err) return reject(err);return resolve(decoded.payload);});return promise;
};

helper.crypto.js(使用AES对参数加解密)

const cryptoJS = require("crypto-js");
const { CryptoKey } = require("../config");
const { jsonToString, stringToJson } = require("utils-lib-js");
const defaultOpt = {mode: cryptoJS.mode.ECB,padding: cryptoJS.pad.Pkcs7,
};
const __key = CryptoKey; // 加密关键字
// 加密
const setCrypto = ({ data, key = __key, opts = defaultOpt }) => {return cryptoJS.AES.encrypt(jsonToString(data), key, opts);
};
// 解密
const getCrypto = ({str,key = __key,resToStr = true,opts = defaultOpt,
}) => {str = decodeURIComponent(str); //前端传参有特殊字符(中文)时转义(替换百分号)const bytes = cryptoJS.AES.decrypt(str, key, opts);const source = bytes.toString(cryptoJS.enc.Utf8);return resToStr ? stringToJson(source) : source;
};
module.exports = {setCrypto,getCrypto,
};

client.js(客户端)

const { createRandom } = require("./utils/helper.random");
const { setCrypto } = require("./utils/helper.crypto");
const { messageCenter } = require("event-message-center");
const { initServer } = require("./server");
const { catchAwait } = require("utils-lib-js");
let __token = null;
// 登录信息
const userInfo = {username: "zhangsan",password: "123123",
};
// 初始化服务端
initServer();
// 客户端加密混淆操作
const encryption = ({ query = {}, key = "params", token = __token }) => {query.id = createRandom(); //生成随机id混淆参数query.token = token;return {[key]: setCrypto({ data: query }).toString(),};
};
// 模拟前端用户登录操作
const userLogin = (query) => {const params = encryption({ query });return messageCenter.invoke("/login", params);
};
// 模拟登录成功后请求
const getInfo = (query) => {const params = encryption({ query });return messageCenter.invoke("/info", params);
};
// 初始化函数
const init = async () => {const [err, res] = await catchAwait(userLogin(userInfo));if (err) return console.error(err);__token = res.token;const [err2, info] = await catchAwait(getInfo());if (err2) return console.error(err2);console.log(info);
};
init();

server.js(服务端)

const { messageCenter } = require("event-message-center");
const { defer, catchAwait } = require("utils-lib-js");
const { getCrypto } = require("./utils/helper.crypto");
const { createBcrypt, checkBcrypt } = require("./utils/helper.bcrypt");
const { createToken, checkToken } = require("./utils/helper.jwt");
const __temp = new Map(); // 将请求过的id存起来(后续可以加定时任务清除缓存,或者增加长度限制)
const userInfo = {// 指代数据库取数据username: "zhangsan",password: createBcrypt("123123"),
};
// 解密操作
const decrypt = (query) => {return getCrypto({ str: query });
};
// 请求去重
const checkRepeat = (query = {}) => {const __id = query.id;if (!!!__id || __temp.has(__id)) return;return __temp.set(__id, query);
};
// 抛错
const promiseRej = (err) => Promise.reject(err);
// 加个简单的中间件,做校验
const middleware = {decrypt: (data) => {// 解密,重复请求校验const { resolve, reject, promise } = defer();const params = decrypt(data.params);if (!!!checkRepeat(params)) reject("重复请求或id为空");else resolve(params);return promise;},token: async ({ token, ...data }) => {// token校验const { resolve, reject, promise } = defer();const [err, username] = await catchAwait(checkToken({ token }));if (err) reject("token过期或失效");else resolve({ ...data, username });return promise;},checkPassword: async (data) => {// 密码校验const { resolve, reject, promise } = defer();if (!!!checkBcrypt(data.password, userInfo.password)) reject("密码错误");else resolve(data);return promise;},chackUser: async (data) => {// 用户校验const { resolve, reject, promise } = defer();if (data.username !== userInfo.username) reject("没找到用户");else resolve(data);return promise;},
};exports.initServer = () => {messageCenter.watch("/login", async (data) => {const [err, params] = await catchAwait(middleware.decrypt(data));const [err2, params2] = await catchAwait(middleware.checkPassword(params));if (err || err2) return promiseRej(err ?? err2);return { token: createToken({ payload: params2.username }) };});messageCenter.watch("/info", async (data) => {const [err, params] = await catchAwait(middleware.decrypt(data));const [err2, params2] = await catchAwait(middleware.token(params));const [err3, params3] = await catchAwait(middleware.chackUser(params2));if (err || err2 || err3) return promiseRej(err ?? err2 ?? err3);return { msg: "获取成功", username: params3.username };});
};

实现效果

将init函数多执行几次,发现参数均不相同。

那么此时传递相同的参数会发生什么?

可以看到,总共发送了五次请求,只有一次返回了结果,其余的全被中间件阻止

写在最后

感谢你耐心的看到了最后,如果文章对你有帮助还望多多支持,感谢!

源码:myCode: 基于js的一些小案例或者项目 - Gitee.com

JS案例:接口加解密与防重放相关推荐

  1. Python实现各种加密,接口加解密不说难

    Hi,大家好.我们在接口自动化测试项目中,有时候需要一些加密.今天给大伙介绍Python实现各种加密,接口加解密再也不愁. 目录 一.项目加解密需求分析 二.Base64加密 三.MD5加密 四. s ...

  2. 软件测试 接口测试 接口鉴权 token鉴权 Mock Server 接口加解密 接口签名sign

    文章目录 1 接口鉴权 1.1 cookie鉴权 1.2 session鉴权 1.3 token鉴权 1.4 Postman的鉴权方式 2 Mock Server 3 接口加解密 3.1 加密方式 3 ...

  3. 老大一个接口加解密临时任务丢了过来,我却肝了3天,感觉可以收拾工位了

    点击上方关注 "终端研发部" 设为"星标",和你一起掌握更多数据库知识 这日,刚撸完2两代码,正准备掏出手机摸鱼放松放松,只见老大朝我走过来,并露出一个&quo ...

  4. html+css+js 做一个加解密小网页

    孩子第一次做网页,比较菜,勿喷 本来是想做一个ctf的知识站和加解密站当作业交上去,但是时间太短了,又要准备高数和大雾简直人都要没了,就只写了base64,凯撒,和栅栏密码 html <!DOC ...

  5. 京东商品接口加解密算法解析

    最近,闲来没事,打开看了一下京东图书的热销榜,想通过接口查看下它接口的加密方式,于是直接打开了M站的地址:https://m.jd.com/,然后打开搜索页面,如下图. 打开页面,打开开发者工具,往下 ...

  6. js的3des加解密和c#.net后台解密

    注意事项: 前台使用cryptojs和自定义的加密js方法实现 后台使用标准的加密算法加密的密码为24位非弱健key 前台代码: <%@ Page Language="C#" ...

  7. JS前端接口加密/解密

    CryptoJS (crypto.js) 为 JavaScript 提供加密和解密算法.目前已支持的算法包括 crypto, Hash, MD5, SHA1, SHA-1, SHA256, SHA-2 ...

  8. 接口参数加解密,代码无侵入这样做方便多了

    为啥接口加解密 在我们做接口的时候,如果是外部用户直接能看到我们的参数,可能会造成我们的接口不安全,比如直接用明文的参数请求我们的接口,把参数自己定义,脏数据就会存到我们的数据库中,严重的话导致我们的 ...

  9. aes解密算法 java_AES算法实现Java和JS互通加解密

    实际开发中客户端与服务端的通信内容往往需要通过密文传输,本文将介绍可以实现Java与js的互相加解密的AES加密方式 Java语言实现 public class AESTest { //static ...

最新文章

  1. day16 递归函数
  2. ubuntu sublime字体设置
  3. Web Application:Exploded和Web Application:Archive
  4. ubuntun中文读书笔记
  5. Ranger架构剖析
  6. 使用Android Studio打包app
  7. 软件测试52讲-测试新技术篇
  8. vue-router 源码:实现一个简单的 vue-router
  9. 防盗链Nginx设置图片防盗链,设置无效的请仔细看红字
  10. 未来教育计算机二级c语言程序设计题,未来教育版计算机二级C语言题库.doc
  11. HADOOP学习_grep和wordcount的例子
  12. intel 9260AC网卡修改成Killer 1550
  13. Flutter29,毕向东java基础全套视频教程百度网盘
  14. Hbase数据库安装
  15. Windows timeout命令
  16. db2 matlab实现,MATLAB MIMO-OFDM无线通信技术及 实现一书的源码和配套英文书267万源代码下载- www.pudn.com...
  17. kafka消费组和分区关系详解
  18. uniapp写微信授权登录
  19. 【玖哥乱弹】神通广大的JavaScript
  20. EasyPR--一个开源的中文车牌识别系统

热门文章

  1. Android APK脱壳--腾讯乐固、360加固一键脱壳 亲测可用
  2. 软件测试工程师考核标准,(软件测试工程师考核标准.docx
  3. 至少包含一个小写字母、大写字母、特殊符号和数字,长度为8-30个字符
  4. 海康工业相机功能模块-IO输入输出控制
  5. matlab如何实现整除的编码
  6. qpython3下载不了_QPython3
  7. echart省会流向图(物流运输、地图)
  8. Log4j2远程日志
  9. UG在钣金设计与制造中的应用
  10. 博勒飞粘度计物质粘度的测定原理、方法