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

news2025/3/20 9:42:38

引言

在上一篇文章中,分享了 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 md5

from Crypto.Cipher import AES
from Crypto.Util.Padding import pad, unpad
from flask import Flask, request, Response

app = 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 True
    else:
        return False


@app.post('/')
def index():
    if not check_token(request.headers.get('x-token')):
        return Response('token expired!', 401)
    data = request.json
    key = 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.coloradmin.cn/o/2251406.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

PDF view | Chrome PDF Viewer |Chromium PDF Viewer等指纹修改

1、打开https://www.browserscan.net/zh/ 2、将internal-pdf-viewer改为 internal-pdf-viewer-jdtest看下效果&#xff1a; 3、源码修改&#xff1a; third_party\blink\renderer\modules\plugins\dom_plugin_array.cc namespace { DOMPlugin* MakeFakePlugin(String plugin_…

2024143读书笔记|《遇见》——立在城市的飞尘里,我们是一列忧愁而又快乐的树

2024143读书笔记|《遇见》——立在城市的飞尘里&#xff0c;我们是一列忧愁而又快乐的树 第1章 年年岁岁岁岁年年第2章 遇见第3章 有个叫“时间”的家伙走过第4章 初雪第6章 回首风烟 《华语散文温柔的一支笔&#xff1a;张晓风作品集&#xff08;共5册&#xff09;》作者张晓风…

python基础(五)

正则表达式 在编写处理字符串的程序或网页时&#xff0c;经常会有查找符合某些复杂规则的字符串的需要。正则表达式就是用于描述这些规则的工具。换句话说&#xff0c;正则表达式就是记录文本规则的代码。 符号解释示例说明.匹配任意字符b.t可以匹配bat / but / b#t / b1t等\…

【连接池】.NET开源 ORM 框架 SqlSugar 系列

.NET开源 ORM 框架 SqlSugar 系列 【开篇】.NET开源 ORM 框架 SqlSugar 系列【入门必看】.NET开源 ORM 框架 SqlSugar 系列【实体配置】.NET开源 ORM 框架 SqlSugar 系列【Db First】.NET开源 ORM 框架 SqlSugar 系列【Code First】.NET开源 ORM 框架 SqlSugar 系列【数据事务…

《业务流程--穿越从概念到实践的丛林》读后感一:什么是业务流程

1.4 流程建模 画流程图常见的方法派别如下: 1)流图。美国国家标准协会(ANSI)制定的规范,利用VISIO中的流程符号进行画图。 2)事件驱动流程链(EPC)。ARIS(集成信息系统架构)。认为流程是由一系列事件触发,并且 针对事件的行为又将引发新的事件,流程的表现为“事件--功…

Sybase数据恢复—Sybase数据库无法启动,Sybase Central连接报错的处理案例

Sybase数据库数据恢复环境&#xff1a; Sybase数据库版本&#xff1a;SQL Anywhere 8.0。 Sybase数据库故障&分析&#xff1a; Sybase数据库无法启动。 错误提示&#xff1a; 使用Sybase Central连接报错。 数据库数据恢复工程师经过检测&#xff0c;发现Sybase数据库出现…

redis基础spark操作redis

Redis内存淘汰策略 将Redis用作缓存时&#xff0c;如果内存空间用满&#xff0c;就会自动驱逐老的数据。 为什么要使用内存淘汰策略呢&#xff1f; 当海量数据涌入redis&#xff0c;导致redis装不下了咋办&#xff0c;我们需要根据redis的内存淘汰策略&#xff0c;淘汰一些不那…

C++学习日记---第14天(蓝桥杯备赛)

笔记复习 1.对象的初始化和清理 对象的初始化和清理是两个非常重要的安全问题&#xff0c;一个对象或者变量没有初始状态&#xff0c;对其使用后果是未知&#xff0c;同样的使用完一个对象或者变量&#xff0c;没有及时清理&#xff0c;也会造成一定的安全问题 构造函数&…

Unity ShaderLab 实现3D物体描边

实现思路&#xff1a; 给物体添加第二个材质球&#xff0c;在shader的顶点着色器中使顶点的位置变大&#xff0c;然后在片元着色器中输出描边颜色。 shader Graph实现如下&#xff1a; ShaderLab实现如下&#xff1a; Shader "Custom/Outline" {Properties{[HDR]_…

【HarmonyOS NEXT】ACL 受限权限申请

关键词&#xff1a;受限开放权限、ACL、鸿蒙 在鸿蒙应用开发过程中&#xff0c;部分权限被受到限制&#xff08;如悬浮窗开发、读取联系人数据、读取公共目录音频文件等权限&#xff09;&#xff0c;但是在我们的应用开发过程中又不得不使用该权限时可向华为申请受限权限&#…

南京仁品耳鼻喉专科医院:12月启动公益义诊月

专业医疗资源送至“家门口”&#xff01;南京仁品耳鼻喉专科医院启动公益义诊月 随着2024年即将步入尾声&#xff0c;南京仁品耳鼻喉医院为回馈社会&#xff0c;提升公众健康福祉&#xff0c;将于12月隆重推出“三甲专家公益义诊月”活动。此次活动旨在通过汇聚众多耳鼻喉领域…

【UE5 C++课程系列笔记】06——定时器的基本使用

目标 使用定时器每秒调用函数打印一句日志信息&#xff0c;并在调用一定次数后停止定时器。 步骤 1. 新建一个Actor类&#xff0c;这里命名为 2. 先在“TimerActor.cpp”中获取定时器管理器 使用定时器管理器来设置定时器&#xff0c;该定时器在2s后启动&#xff0c;然后每…

数据分析的尽头是web APP?

数据分析的尽头是web APP&#xff1f; 在做了一些数据分析的项目&#xff0c;也制作了一些数据分析相关的web APP之后&#xff0c;总结自己的一些想法和大家分享。 1.web APP是呈现数据分析结果的另外一种形式。 数据分析常见的结果是数据分析报告&#xff0c;可以是PPT或者…

看不见的彼方:交换空间——小菜一碟

有个蓝色的链接&#xff0c;先去看看两年前的题目的write up &#xff08;https://github.com/USTC-Hackergame/hackergame2022-writeups/blob/master/official/%E7%9C%8B%E4%B8%8D%E8%A7%81%E7%9A%84%E5%BD%BC%E6%96%B9/README.md&#xff09; 从别人的write up中了解到&…

以达梦为数据库底座时部署的微服务页面报乱码,调整兼容模式

1.问题描述 部署微服务&#xff0c;文件、代码是延用的mysql类型的&#xff0c;部署前做了部分适配&#xff0c;但是在使用dm数据库进行安装的服务在页面上查询出的数据却都是乱码 2.查询官网&#xff0c;注意到一个参数COMPATIBLE_MODE兼容模式的配置 考虑是延用mysql&…

K2升班卷(C++ 3道题)

目录 1.匹配 题目背景 题目描述 输入格式 输出格式 输入输出样例 说明/提示 样例 1 解释 数据规模与约定 提示 2.乘方 题目描述 输入格式 输出格式 输入输出样例 数据规模与约定 3.缺水的王国 题目描述 输入格式 输出格式 输入输出样例 说明/提示 样例解…

Redis(4):主从复制

一、主从复制概述 主从复制&#xff0c;是指将一台Redis服务器的数据&#xff0c;复制到其他的Redis服务器。前者称为主节点(master)&#xff0c;后者称为从节点(slave)&#xff1b;数据的复制是单向的&#xff0c;只能由主节点到从节点。   默认情况下&#xff0c;每台Redis…

Educator头歌:离散数学 - 图论

第1关&#xff1a;图的概念 任务描述 本关任务&#xff1a;学习图的基本概念&#xff0c;完成相关练习。 相关知识 为了完成本关任务&#xff0c;你需要掌握&#xff1a;图的概念。 图的概念 1.一个图G是一个有序三元组G<V,R,ϕ>&#xff0c;其中V是非空顶点集合&am…

linux模拟HID USB设备及wireshark USB抓包配置

文章目录 1. 内核配置2. 设备配置附 wireshark USB抓包配置 linux下模拟USB HID设备的简单记录&#xff0c;其他USB设备类似。 1. 内核配置 内核启用USB Gadget&#xff0c;使用fs配置usb device信息。 Device Drivers ---> [*] USB support ---><*> USB …

Trimble X12助力电力管廊数据采集,为机器人巡视系统提供精准导航支持

地下电缆是一个城市重要的基础设施&#xff0c;它不仅具有规模大、范围广、空间分布复杂等特点&#xff0c;更重要的是它还承担着信息传输、能源输送等与人们生活息息相关的重要功能&#xff0c;也是一个城市赖以生存和发展的物质基础。 01、项目概述 本次项目是对某区域2公里左…