通用技术 记一次加密接口请求脚本编写

狂天 · 2024年04月29日 · 最后由 chrislee 回复于 2024年05月11日 · 8079 次阅读

公司出于安全考虑,要对新接口进行加密,并要求测试性能,于是我就揽下这个任务。
从开发那里得知接口的加密方式是对参数进行 AES 加密,我打开 pycharm 轻轻松松写了一个 AES 加密方法,就等着提测了。
提测后用这个方法加密完参数一提交,接口频频提示参数错误。
我???
我去找开发,开发说你的参数里缺少 “签名”,我们的参数体中增加了一个签名,这个签名是通过部分参数的组分计算得出。
我觉得有点复杂,直接把开发的 java 代码要过来,然后对着 java 代码一步一步在 python 里实现。
我已经完全把逻辑复制过来了,可一提交仍然报错,再一看还是签名错误,我不解,拉开发一块 review 我的代码。
开发虽然不了解 python 但是逻辑大概能看明白,开发也认为我的实现挺完整了,就是不明白问题出在哪。
机智如我想到,反解一下不就行了!
反解开发和我的签名对比下原始参数,实现一样,那可能问题出在参数有差异上。
结果呢,因为签名使用的是哈希函数,无法反解,我的好主意就此作罢。😅
下午我的领导问我进度,我这还一筹莫展呢,领导没说话就走了。
我这一下压力就来了,搞个压测,一天了,连接口都没跑通呢,你这是在干啥?
心里一急,一下想到,我要不直接用开发的代码加密?
一想可以试试,打开 IDEA,就把开发的代码放进去,一运行,还真可以生成签名,只不过签名还是不对。
这下基本可以确定了,一定是参数不一致。
于是我对比了开发的传参和我的传参,发现我传参的字段顺序与开发的不一致,而哈希函数需要的参数是一个字符串,也就是说字段顺序不一致会有影响。
我固定的 json 里面的字段顺序。
再一跟开发的签名,果然一致了!
之后从网上 copy 了 AES 加密的 JAVA 工具类,对参数进行加密,一请求接口,成功!

写的文字量还成,实际上这两天心情真是……我一度觉得自己可能搞不定这项任务了,
一点一点摸索,最终完成脚本,还是比较有成就感的。
今年上半年突破了这一个挑战,算是有些收获。

共收到 10 条回复 时间 点赞

你们的签名不是固定的吗?

好一篇流水席~
单说这个 “签名” 的生成,如果不影响接口处理逻辑的话可以直接采用拿来主义

19 年写的

import hashlib
import base64
from public.api_common import api_sign,project_type
from public.log import logger
# mylog=logger('验签模块').get_logger()
class checkSign:
    # 初始化传入dict
    def __init__(self, dict):
        # mylog.info(f"请求参数:{dict}")
        # 不改变传入的data=>直接对字典进行复制
        data = dict.copy()
        self.dict = data

    def check_dict(self):
        # 首先判断字典是否空,为空直接加密
        if not self.dict:
            string = ''
            if project_type != 3:
                return {"X-MPMALL-Sign": self.__sign(string)}
            else:
                return {"X-Sign": self.__sign(string)}
        else:
            # 非空字典,过滤value为空和嵌套字典、列表
            for k, v in list(self.dict.items()):
                if v == '' or v is None:
                    self.dict.pop(k)
                for k, v in list(self.dict.items()):
                    if type(
                            self.dict[k]).__name__ == 'dict'or type(
                            self.dict[k]).__name__ == 'list':
                        self.dict.pop(k)
            # 对字典进行ASCII码排序
            new_list = sorted(self.dict.items())
            alist = []
            for i in new_list:
                data = '&' + str(i[0]) + '=' + str(i[1])
                alist.append(data)
            new_string = ''.join(alist)
            if project_type != 3:
                return {"X-MPMALL-Sign": self.__sign(new_string)}
            else:
                return {"X-Sign": self.__sign(new_string)}
    # 私有方法,生成签名

    def __sign(self, string):
        if string:
            sign = string[1:] + '&key=' + api_sign  # 测试环境
            m = hashlib.md5()
            m.update(sign.encode("utf8"))
            encodeStr = m.hexdigest()
            base_code = base64.b64encode(encodeStr.encode('utf-8'))
            print(api_sign)
            return str(base_code, 'utf-8')
        else:
            sign = 'key=' + api_sign
            m = hashlib.md5()
            m.update(sign.encode("utf8"))
            encodeStr = m.hexdigest()
            base_code = base64.b64encode(encodeStr.encode('utf-8'))
            return str(base_code, 'utf-8')
花菜 回复

赞同这种做法。

没太大必要自己硬搞,最务实的做法还是复用开发的代码,也避免开发变更自己这边跟着出错。

搞得出来还算有结果,要是搞不出来,就是扣分。

是的,研发都是用 java,可以复用研发的加密方法合在自己的接口请求里面实现,效率最高。

最佳实践方案就是把研发的代码扔进 chatgpt 转化成 python 版本

服务是 java 的话脚本也用 java 写会好点?正常这种工具类都有个公共的依赖,之前都是直接引用他们的依赖,自己写费时费力还得对签名算法😂

现在不都直接甩给 gpt 吗,三方对接花一天,扔给 gpt 翻译成 python 30 分钟调试完

但凡对于一个 request 进行加签,request 是个 json,那么基本上就是转换成 map 了。而 map 的排序不指定的话,极有可能在不同的机器或者 jvm 的版本上(我是用 java 的)是不一致的。最后加签出来的结果就是不一致的。
这个可以说是 common sence 了

需要 登录 后方可回复, 如果你还没有账号请点击这里 注册