httprunner學習23-加解密

前言

有些接口的請求參數是加密的,返回的接口內容也是須要解密才能看到。html

加密接口

好比當咱們訪問下面這個登錄的接口時,請求參數帳號和密碼都是須要加密,經過parms參數傳過去,服務器才能識別到python

沒加密的時候,請求參數應該是json

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

返回的結果,解密後應該是api

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

像這種接口,作接口自動化的時候,請求參數應該用未加密以前的測試參數,這樣方便維護和修改,在發請求的過程當中先對請求參數加密。
具體的加密規則和方法,得看開發的加密規則了,好比參考這篇的加密http://www.javashuo.com/article/p-rnlakoqm-ew.html服務器

hrun腳本編寫

寫腳本的時候,yaml文件寫未加密的時候,原始的測試數據app

-   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裏面去寫一個dom

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('\0')
        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\0\0\0\0\0\0\0\0')  # 初始化密鑰
    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:\soft\HELL\DEMO>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:\soft\HELL\DEMO\reports\1571850793.html
相關文章
相關標籤/搜索