如何使用Postman优雅地进行接口自动加密与解密

引言

在上一篇文章中,分享了 Requests 自动加解密的方法,本篇文章分享一下更加方便的调试某个服务端接口。

Postman

Postman 这个工具后端小伙伴应该相当熟悉了,一般情况下我们会在开发和逆向过程中使用它来快速向接口发送请求,通过接口返回值来判断传入的接口参数是否正确。

在开发或者逆向过程中,有的时候接口的参数和返回值是加密的,有的时候还要先调用接口申请一个临时的 token 才能正常发送后续请求,这个时候我们要么就是用 Python 写一小段代码来验证接口逻辑是否正确,要么就是手动加密后再使用 Postman 发送请求,效率比较低,体验不太好。

这个时候,Postman 的自动加解密功能就派上用场了,我们可以使用 Postman 的脚本功能来自动实现这一功能。Postman 的脚本功能在很久之前就提供了,但是大家用的还比较少,我这里分享两个例子供大家参考,大家在用到的时候可以根据我的例子进行修改以实现自己的逻辑。

Pre-request

Pre-request 功能可以在 Postman 发送请求之前提前做一些事情,例如获取 token,计算签名,加密数据等等。

Post-request

Post-request 功能可以在 Postman发送请求收到响应后做一些事情,例如解密数据,验证签名等等。

测试服务端

为了方便验证 Postman 两个脚本的功能,我这里写了一个简单的服务端。只是 demo 代码,请大家不要吐槽哈

import base64
import json
import time
import uuid
from hashlib import md5from Crypto.Cipher import AES
from Crypto.Util.Padding import pad, unpad
from flask import Flask, request, Responseapp = Flask(__name__)# 别问我为啥不清缓存,问就是忘了
token_cache = {}def get_nonce():return uuid.uuid4().__str__()def encrypt(k, data, mode=AES.MODE_ECB):aes = AES.new(k.encode(), mode)result = aes.encrypt(pad(data.encode(), block_size=16))return base64.b64encode(result).decode()def decrypt(k, data, mode=AES.MODE_ECB):aes = AES.new(k.encode(), mode)result = aes.decrypt(base64.b64decode(data))return unpad(result, block_size=16).decode()def get_headers():return {'Content-Type': 'application/json','x-encrypt': 'true','nonce': get_nonce()}@app.get('/get_token')
def get_token():token = str(uuid.uuid4())token_cache[token] = int(time.time())return {'token': token}def check_token(token):if token in token_cache and int(time.time()) - token_cache[token] <= 5:return Trueelse:return False@app.post('/')
def index():if not check_token(request.headers.get('x-token')):return Response('token expired!', 401)data = request.jsonkey = request.headers.get('x-key')print(f"get timestamp is :{request.headers.get('x-timestamp')}")print(f"get sign is :{request.headers.get('x-sign')}")print(f"get key is :{key}")print(f'encrypt json data is:{data}')decrypt_data = decrypt(key, data['data'])print(f'decrypt json data is:{decrypt_data}')assert md5(request.headers.get('x-timestamp').encode()).hexdigest() == request.headers.get('x-sign')headers = get_headers()data = {'data': str(json.loads(decrypt_data)['data'] * 2) + (request.headers.get('x-sign') or '')}print(f'before encrypt data is:{data}')encrypt_key = headers.get('nonce').replace('-', '')[:16]print(f'encrypt key is :{encrypt_key}')d = encrypt(encrypt_key, json.dumps(data))print(f'after encrypt data is:{d}')return Response(json.dumps({'data': d}), headers=headers, mimetype='application/json')if __name__ == '__main__':app.run(debug=True, port=8888)

脚本具有以下功能:

  • 每个请求都要带有一个 token,可以通过 get_token 接口获取 token 值,token 过期时间 5 秒
  • 请求体是加密的,要先解密才能获取原始数据
  • 每个请求都带有 sign 值,获取到请求后要先验证 sign 值是否正确
  • 请求加密密钥在 x-key 请求头上,使用字符串去掉-后的前 16 位来解密数据,相反的,客户端使用同样的方式来加密
  • 处理数据,这里为了演示,只是将收到的数据复制了一份并且加上请求的 x-sign 值然后返回给客户端
  • 数据通过同样的方式进行加密,加密密钥在 nonce 响应头中

Pre-request 脚本

先看发送前的脚本:

const CryptoJS = require('crypto-js');
const { v4: uuidv4 } = require('uuid');
let token='';
try {const response = await pm.sendRequest({url: "http://127.0.0.1:8888/get_token",method: "GET"});console.log(response.json().token);token=response.json().token;
} catch (err) {console.error(err);
}
var timestamp = Math.floor(Date.now() / 1000);
const bodyObject = JSON.parse(pm.request.body.raw);
console.log(timestamp);
const uuid = uuidv4();
console.log(uuid);
const uuid_key=uuid.replace(/-/g,'').substring(0,16);
console.log(uuid_key);
pm.request.headers.add({"key": "x-token","value": token
});
pm.request.headers.add({"key": "x-timestamp","value": timestamp.toString()
});
pm.request.headers.add({"key":"x-sign","value": CryptoJS.MD5(timestamp.toString()).toString()
})
pm.request.headers.add({"key":"x-key","value": uuid_key
})
const key = CryptoJS.enc.Utf8.parse(uuid_key);const encryptedData = CryptoJS.AES.encrypt(JSON.stringify(bodyObject), key, {mode: CryptoJS.mode.ECB,padding: CryptoJS.pad.Pkcs7
}).toString();
console.log(encryptedData);
const newBody = {"data": encryptedData
};pm.request.body.raw = JSON.stringify(newBody);

Pre 脚本具有以下逻辑:

  • 先访问 get_token 接口获取临时的 token
  • 获取时间戳,解析请求的 body
  • 获取 uuid 按照正常的规则生成密钥
  • token,时间戳,signkey 字段设置到请求头上
  • 加密数据,然后替换原始的请求 body

Post-request 脚本

来看收到响应后的脚本:

const CryptoJS = require('crypto-js');
pm.test("Status code is 200", function () {pm.response.to.have.status(200);
});
const bodyObject = pm.response.json();
const encryptedData=bodyObject['data']
console.log(encryptedData)const nonce=pm.response.headers.get('nonce');
console.log(nonce);
const key=nonce.replace(/-/g,'').substring(0,16)
console.log(key);const decryptedData = CryptoJS.AES.decrypt(encryptedData, 
CryptoJS.enc.Utf8.parse(key), {mode: CryptoJS.mode.ECB,padding: CryptoJS.pad.Pkcs7}).toString(CryptoJS.enc.Utf8);console.log(decryptedData);var template = `{{response}}  
`;// Set visualizer
pm.visualizer.set(template, {// Pass the response body parsed as JSON as `data`response:decryptedData
});

Post 脚本具有以下逻辑:

  • 先通过 Postman 自带的test 方法判断状态码是否是 200
  • 获取加密后的 data 数据,获取请求头中的 nonce 字段,计算出密钥
  • 使用计算出来的密钥解密上面获取到的加密数据,得到原始数据
  • 使用 Postman 自带的 visualizer 方法来展示解密后的数据

以上两个脚本大家可以当做参考,这里只是作为一个示例。

请求演示

在这里插入图片描述

在这里插入图片描述

先看效果,请求的时候 body 是明文的,请求后获取到的响应是加密的,scripts 就是脚本的位置,右边还有一些代码片段可以供参考, 脚本的功能还有很多,例如获取环境变量,设置全局变量,发送请求等等,大家可以自行选择。可以在 Console 界面查看脚本的日志。

在这里插入图片描述

那在哪里查看解密后的数据呢,在 Visualize 中。平时大家基本上都是在 Pretty 中查看响应,响应可以被自动格式化,但是目前为止,我还没查到如何能修改 Postman 的响应,只能通过 Visualize 的方式将解密后的响应展示出来,如果有知道的小伙伴可以留言评论。

在这里插入图片描述

抓包验证

在这里插入图片描述

在这里插入图片描述

从抓包的结果来看,数据在请求和响应中都是加密的状态,但是在 Postman 中可以实时看到解密后的响应。

总结

以上就是通过 Postman 脚本来自动加解密的方法,有需要的小伙伴可以自行修改代码以提升接口调试的效率。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/478822.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Spring Boot——统一功能处理

1. 拦截器 拦截器主要用来拦截用户的请求&#xff0c;在指定方法前后&#xff0c;根据业务需要执行设定好的代码&#xff0c;也就是提前定义一些逻辑&#xff0c;在用户的请求响应前后执行&#xff0c;也可以在用户请求前阻止其执行&#xff0c;例如登录操作&#xff0c;只有登…

PYTORCH基础语法知识

初识Torch PyTorch&#xff0c;简称Torch&#xff0c;主流的经典的深度学习框架&#xff0c;深度学习的框架。 简介 PyTorch是一个基于Python的深度学习框架&#xff0c;它提供了一种灵活、高效、易于学习的方式来实现深度学习模型。PyTorch最初由Facebook开发&#xff0c;被…

C嘎嘎探索篇:栈与队列的交响:C++中的结构艺术

C嘎嘎探索篇&#xff1a;栈与队列的交响&#xff1a;C中的结构艺术 前言&#xff1a; 小编在之前刚完成了C中栈和队列&#xff08;stack和queue&#xff09;的讲解&#xff0c;忘记的小伙伴可以去我上一篇文章看一眼的&#xff0c;今天小编将会带领大家吹奏栈和队列的交响&am…

刷题日常(数据流中的中位数,逆波兰表达式求值,最长连续序列,字母异位词分组)

数据流中的中位数 描述 如何得到一个数据流中的中位数&#xff1f;如果从数据流中读出奇数个数值&#xff0c;那么中位数就是所有数值排序之后位于中间的数值。如果从数据流中读出偶数个数值&#xff0c;那么中位数就是所有数值排序之后中间两个数的平均值。我们使用Insert()…

SQL 复杂查询

目录 复杂查询 一、目的和要求 二、实验内容 &#xff08;1&#xff09;查询出所有水果产品的类别及详情。 查询出编号为“00000001”的消费者用户的姓名及其所下订单。&#xff08;分别采用子查询和连接方式实现&#xff09; 查询出每个订单的消费者姓名及联系方式。 在…

uniapp-vue2引用了vue-inset-loader插件编译小程序报错

报错信息 Error: Vue packages version mismatch: - vue3.2.45 (D:\qjy-myApp\admin-app\node_modules\vue\index.js) - vue-template-compiler2.7.16 (D:\qjy-myApp\admin-app\node_modules\vue-template-compiler\package.json) This may cause things to work incorrectly.…

VOLO实战:使用VOLO实现图像分类任务(二)

文章目录 训练部分导入项目使用的库设置随机因子设置全局参数图像预处理与增强读取数据设置Loss设置模型设置优化器和学习率调整策略设置混合精度&#xff0c;DP多卡&#xff0c;EMA定义训练和验证函数训练函数验证函数调用训练和验证方法 运行以及结果查看测试完整的代码 在上…

【Linux】TCP网络编程

目录 V1_Echo_Server V2_Echo_Server多进程版本 V3_Echo_Server多线程版本 V3-1_多线程远程命令执行 V4_Echo_Server线程池版本 V1_Echo_Server TcpServer的上层调用如下&#xff0c;和UdpServer几乎一样&#xff1a; 而在InitServer中&#xff0c;大部分也和UDP那里一样&…

XG(S)-PON原理

前言 近年来&#xff0c;随着全球范围内接入市场的飞快发展以及全业务运营的快速开展&#xff0c;已有的PON技术标准在带宽需求、业务支撑能力以及接入节点设备和配套设备的性能提升等方面都面临新的升级需求XG(S)-PON(10G GPON)是在已有GPON技术标准上演进的增强下一代GPON技…

C语言学习 12(指针学习1)

一.内存和地址 1.内存 在讲内存和地址之前&#xff0c;我们想有个⽣活中的案例&#xff1a; 假设有⼀栋宿舍楼&#xff0c;把你放在楼⾥&#xff0c;楼上有100个房间&#xff0c;但是房间没有编号&#xff0c;你的⼀个朋友来找你玩&#xff0c;如果想找到你&#xff0c;就得挨…

前端---CSS(部分用法)

HTML画页面--》这个页面就是页面上需要的元素罗列起来&#xff0c;但是页面效果很差&#xff0c;不好看&#xff0c;为了让页面好看&#xff0c;为了修饰页面---》CSS CSS的作用&#xff1a;修饰HTML页面 用了CSS之后&#xff0c;样式和元素本身做到了分离的效果。---》降低了代…

H.265流媒体播放器EasyPlayer.js无插件H5播放器关于移动端(H5)切换网络的时候,播放器会触发什么事件

EasyPlayer.js无插件H5播放器作为一款功能全面的H5流媒体播放器&#xff0c;凭借其多种协议支持、多种解码方式、丰富的渲染元素和强大的应用功能&#xff0c;以及出色的跨平台兼容性&#xff0c;为用户提供了高度定制化的选项和优化的播放体验。无论是视频直播还是点播&#x…

零基础学安全--云技术基础

目录 学习连接 前言 云技术历史 云服务 公有云服务商 云分类 基础设施即服务&#xff08;IaaS&#xff09; 平台即服务&#xff08;PaaS&#xff09; 软件即服务&#xff08;SaaS&#xff09; 云架构 虚拟化 容器 云架构设计 组件选择 基础设施即代码 集成部署…

【AI绘画】Midjourney进阶:色调详解(上)

博客主页&#xff1a; [小ᶻ☡꙳ᵃⁱᵍᶜ꙳] 本文专栏: AI绘画 | Midjourney 文章目录 &#x1f4af;前言&#x1f4af;Midjourney中的色彩控制为什么要控制色彩&#xff1f;为什么要在Midjourney中控制色彩&#xff1f; &#x1f4af;色调白色调淡色调明色调 &#x1f4af…

前端适配:常用的几种方案

一、rem和第三方插件 rem与em不同&#xff0c;rem会根据html的根节点字体大小进行变换&#xff0c;例如1rem就是一个字体大小那么大&#xff0c;比如根大小font size为12px&#xff0c;那么1rem即12px&#xff0c;大家可以在网上寻找单位换算工具进行换算&#xff08;从设计稿…

蓝桥杯c++算法秒杀【6】之动态规划【下】(数字三角形、砝码称重(背包问题)、括号序列、异或三角:::非常典型的必刷例题!!!)

别忘了请点个赞收藏关注支持一下博主喵&#xff01;&#xff01;&#xff01;! ! ! ! &#xff01; 关注博主&#xff0c;更多蓝桥杯nice题目静待更新:) 动态规划 三、括号序列 【问题描述】 给定一个括号序列&#xff0c;要求尽可能少地添加若干括号使得括号序列变得合…

AIGC--AIGC与人机协作:新的创作模式

AIGC与人机协作&#xff1a;新的创作模式 引言 人工智能生成内容&#xff08;AIGC&#xff09;正在以惊人的速度渗透到创作的各个领域。从生成文本、音乐、到图像和视频&#xff0c;AIGC使得创作过程变得更加快捷和高效。然而&#xff0c;AIGC并非完全取代了人类的创作角色&am…

Hot100 - 字母异位词分组

Hot100 - 字母异位词分组 最佳思路&#xff1a;排序 时间复杂度&#xff1a; O(nmlogm)&#xff0c;其中 n 为 strs 数组的长度&#xff0c;m 为每个字符串的长度。 代码&#xff1a; class Solution {public List<List<String>> groupAnagrams(String[] strs) …

C++11特性(详解)

目录 1.C11简介 2.列表初始化 3.声明 1.auto 2.decltype 3.nullptr 4.范围for循环 5.智能指针 6.STL的一些变化 7.右值引用和移动语义 1.左值引用和右值引用 2.左值引用和右值引用的比较 3.右值引用的使用场景和意义 4.右值引用引用左值及其一些更深入的使用场景分…

【H2O2|全栈】JS进阶知识(十一)axios入门

目录 前言 开篇语 准备工作 获取 介绍 使用 结束语 前言 开篇语 本系列博客主要分享JavaScript的进阶语法知识&#xff0c;本期主要对axios进行基本的了解。 与基础部分的语法相比&#xff0c;ES6的语法进行了一些更加严谨的约束和优化&#xff0c;因此&#xff0c;在…