zoukankan      html  css  js  c++  java
  • httprunner学习23-加解密

    前言

    有些接口的请求参数是加密的,返回的接口内容也是需要解密才能看到。

    加密接口

    比如当我们访问下面这个登陆的接口时,请求参数账号和密码都是需要加密,通过parms参数传过去,服务器才能识别到

    没加密的时候,请求参数应该是

    {
    	"params": {
    		"username": "test",
    		"password": "123456"
    	}
    }
    

    返回的结果,解密后应该是

    {
    	"code": 0,
    	"msg": "login success!",
    	"datas": {
    		"username": "test",
    		"token": "a003442ffc9645af181d8c768bd8758a250ba6d6"
    	}
    }
    

    像这种接口,做接口自动化的时候,请求参数应该用未加密之前的测试参数,这样方便维护和修改,在发请求的过程中先对请求参数加密。
    具体的加密规则和方法,得看开发的加密规则了,比如参考这篇的加密https://www.cnblogs.com/yoyoketang/p/11717282.html

    hrun脚本编写

    写脚本的时候,yaml文件写未加密的时候,原始的测试数据

    -   config:
            name: testcase description
            variables: {}
    -   test:
            name: /api/v2/login
            request:
                headers:
                    Content-Type: application/json
                    User-Agent: Fiddler
                json:
                    params:
                        password: '123456'
                        username: test
                method: POST
                url: http://49.235.92.12:9000/api/v2/login
            setup_hooks:
            -   ${setup_request($request)}
            validate:
            -   eq:
                - status_code
                - 200
            -   eq:
                - headers.Content-Type
                - application/json
            -   eq:
                - content.code
                - 0
            -   eq:
                - content.msg
                - login success!
    

    接下来只需要把 params 下的参数做加密就可以了,这里用到setup_hooks函数实现, ${setup_request($request)}函数在debugtalk.py里面去写一个

    setup_hooks

    setup_hooks用于在 HTTP 请求发送前执行 hook 函数,主要用于准备工作;也可以实现对请求的 request 内容进行预处理。
    以下是官方文档给的案例

    def setup_hook_prepare_kwargs(request):
        if request["method"] == "POST":
            content_type = request.get("headers", {}).get("content-type")
            if content_type and "data" in request:
                # if request content-type is application/json, request data should be dumped
                if content_type.startswith("application/json") and isinstance(request["data"], (dict, list)):
                    request["data"] = json.dumps(request["data"])
    
                if isinstance(request["data"], str):
                    request["data"] = request["data"].encode('utf-8')
    

    可以依着葫芦画瓢

    from cryptography.hazmat.primitives import padding
    from cryptography.hazmat.primitives.ciphers import algorithms
    from Crypto.Cipher import AES
    from binascii import b2a_hex, a2b_hex
    import json
    
    '''
    AES/CBC/PKCS7Padding 加密解密
    环境需求:
    pip3 install pycryptodome
    '''
    
    class PrpCrypt(object):
    
        def __init__(self, key='1234123412341234'):
            self.key = key.encode('utf-8')
            self.mode = AES.MODE_CBC
            self.iv = b'0102030405060708'
            # block_size 128位
    
        # 加密函数,如果text不足16位就用空格补足为16位,
        # 如果大于16当时不是16的倍数,那就补足为16的倍数。
        def encrypt(self, text):
            cryptor = AES.new(self.key, self.mode, self.iv)
            text = text.encode('utf-8')
    
            # 这里密钥key 长度必须为16(AES-128),
            # 24(AES-192),或者32 (AES-256)Bytes 长度
            # 目前AES-128 足够目前使用
    
            text=self.pkcs7_padding(text)
    
    
            self.ciphertext = cryptor.encrypt(text)
    
            # 因为AES加密时候得到的字符串不一定是ascii字符集的,输出到终端或者保存时候可能存在问题
            # 所以这里统一把加密后的字符串转化为16进制字符串
            return b2a_hex(self.ciphertext).decode().upper()
    
        @staticmethod
        def pkcs7_padding(data):
            if not isinstance(data, bytes):
                data = data.encode()
    
            padder = padding.PKCS7(algorithms.AES.block_size).padder()
    
            padded_data = padder.update(data) + padder.finalize()
    
            return padded_data
    
        @staticmethod
        def pkcs7_unpadding(padded_data):
            unpadder = padding.PKCS7(algorithms.AES.block_size).unpadder()
            data = unpadder.update(padded_data)
    
            try:
                uppadded_data = data + unpadder.finalize()
            except ValueError:
                raise Exception('无效的加密信息!')
            else:
                return uppadded_data
    
        # 解密后,去掉补足的空格用strip() 去掉
        def decrypt(self, text):
            #  偏移量'iv'
            cryptor = AES.new(self.key, self.mode, self.iv)
            plain_text = cryptor.decrypt(a2b_hex(text))
            # return plain_text.rstrip('')
            return bytes.decode(plain_text).rstrip("x01").
                rstrip("x02").rstrip("x03").rstrip("x04").rstrip("x05").
                rstrip("x06").rstrip("x07").rstrip("x08").rstrip("x09").
                rstrip("x0a").rstrip("x0b").rstrip("x0c").rstrip("x0d").
                rstrip("x0e").rstrip("x0f").rstrip("x10")
    
        def dict_json(self, d):
            '''python字典转json字符串, 去掉一些空格'''
            j = json.dumps(d).replace('": ', '":').replace(', "', ',"').replace(", {", ",{")
            return j
    
    def setup_request(request):
        pc = PrpCrypt('12345678')  # 初始化密钥
        params = request.get("json").get("params")
        print("加密前:%s" % params)
        # 对params加密
        en_params = pc.encrypt(json.dumps(params))
        print("解密后:%s" % en_params)
        request["json"]["params"] = en_params
    

    运行用例

    运行用例结构

    D:softHELLDEMO>hrun login_decrype.yml
    /api/v2/login
    加密前:{'password': '123456', 'username': 'test'}
    解密后:3DBF6BE0F8549A98AA81B629A028E487BA2EBE85EF1BC9FE7105F5FE833F1DF26F022E404EFBDAD5A5DF1A7B7FEDA16C
    INFO     POST http://49.235.92.12:9000/api/v2/login
    INFO     status_code: 200, response_time(ms): 467.89 ms, response_length: 209 bytes
    INFO     start to validate.
    .
    
    ----------------------------------------------------------------------
    Ran 1 test in 0.574s
    
    OK
    INFO     Start to render Html report ...
    INFO     Generated Html report: D:softHELLDEMO
    eports1571850793.html
    
  • 相关阅读:
    阿铭每日一题 day 1 20180111
    计算机网络之基础链路
    android学习笔记 对话框合集
    android 音乐播放器简单实现
    Service的生命周期&Service绑定方法
    android学习笔记 Service
    android学习笔记 activity生命周期&任务栈&activity启动模式
    android 短信助手demo
    android 显示意图
    java 多线程断点下载demo
  • 原文地址:https://www.cnblogs.com/yoyoketang/p/11730008.html
Copyright © 2011-2022 走看看