一、为什么接口测试必须处理加解密?
在工业控制、金融支付或政企核心系统中,接口安全防护要求极高。很多后端 API 并不直接接收明文 JSON,而是要求:
- 请求体全密文传输:客户端使用对称加密算法(如 AES-CBC)对整个 JSON 载荷进行加密,再进行 Base64 编码传输;
- 防篡改数字签名:请求头携带基于非对称私钥(RSA)生成的数字签名,服务端使用公钥验签通过后才执行业务;
- 响应体加密解密:服务端返回的也是一段密文字符串,测试框架必须在拿到响应的第一时间将其解密还原为字典才能进行字段断言。
如果测试框架没有抽象出通用的加解密层,编写测试用例将异常痛苦。
二、AES-CBC 模式加解密核心实现
AES(Advanced Encryption Standard)是目前业界使用最广泛的对称加密算法。在 CBC(Cipher Block Chaining)模式下,必须提供 16/24/32 字节的密钥(Key)与 16 字节的初始向量(IV)。
1. 补齐与去除填充(PKCS7 Padding)
AES 的加密块大小固定为 16 字节(128 位)。当明文长度不是 16 的整倍数时,必须进行填充:
python
import base64
import json
from Crypto.Cipher import AES
def pad_bytes(data: bytes, block_size: int = 16) -> bytes:
"""PKCS7 标准补齐:缺失 N 个字节,就填充 N 个值为 N 的字节"""
padding_len = block_size - (len(data) % block_size)
padding = bytes([padding_len] * padding_len)
return data + padding
def unpad_bytes(padded_data: bytes) -> bytes:
"""去除 PKCS7 填充数据"""
padding_len = padded_data[-1]
return padded_data[:-padding_len]2. 加密与解密完整函数(脱敏安全实现)
python
class AesCryptoUtils:
def __init__(self, secret_key: str, iv: str):
# 严格校验密钥长度(32 字节对应 AES-256)与 IV(16 字节)
self.key = secret_key.encode('utf-8')[:32].ljust(32, b'0')
self.iv = iv.encode('utf-8')[:16].ljust(16, b'0')
def encrypt(self, plain_text: str) -> str:
"""明文字符串 -> 加密并 Base64 编码"""
cipher = AES.new(self.key, AES.MODE_CBC, self.iv)
padded_raw = pad_bytes(plain_text.encode('utf-8'))
encrypted_bytes = cipher.encrypt(padded_raw)
return base64.b64encode(encrypted_bytes).decode('utf-8')
def decrypt(self, encrypted_base64: str) -> str:
"""Base64 密文 -> 解密还原明文字符串"""
encrypted_bytes = base64.b64decode(encrypted_base64.encode('utf-8'))
cipher = AES.new(self.key, AES.MODE_CBC, self.iv)
decrypted_raw = cipher.decrypt(encrypted_bytes)
return unpad_bytes(decrypted_raw).decode('utf-8')三、RSA 非对称签名与验签
对于关键控制指令或资产下发操作,通常使用 RSA 私钥进行数字签名:
python
from Crypto.PublicKey import RSA
from Crypto.Signature import pkcs1_15
from Crypto.Hash import SHA256
class RsaSignatureUtils:
@staticmethod
def sign_payload(payload_str: str, private_key_pem: str) -> str:
"""使用 RSA 私钥对请求报文计算 SHA-256 签名"""
private_key = RSA.import_key(private_key_pem)
digest = SHA256.new(payload_str.encode('utf-8'))
signature = pkcs1_15.new(private_key).sign(digest)
return base64.b64encode(signature).decode('utf-8')
@staticmethod
def verify_signature(payload_str: str, signature_b64: str, public_key_pem: str) -> bool:
"""使用 RSA 公钥验证签名有效性"""
public_key = RSA.import_key(public_key_pem)
digest = SHA256.new(payload_str.encode('utf-8'))
signature_bytes = base64.b64decode(signature_b64.encode('utf-8'))
try:
pkcs1_15.new(public_key).verify(digest, signature_bytes)
return True
except (ValueError, TypeError):
return False四、在测试框架层面的优雅集成
在实际编写 pytest 或 requests 客户端时,不要让测试用例手动写加密代码。应通过请求/响应拦截器或自定义 ApiClient 实现全自动处理:
python
def send_secure_api_request(api_path: str, raw_payload: dict) -> dict:
crypto = AesCryptoUtils(secret_key="SECURE_TEST_KEY_32BYTES_LONG000", iv="IV_16BYTES_LONG0")
# 1. 自动加密请求载荷
encrypted_body = crypto.encrypt(json.dumps(raw_payload))
# 2. 发起 HTTP 通信
response = requests.post(f"https://api.example.com{api_path}", data=encrypted_body)
# 3. 自动解密服务端密文响应并反序列化
decrypted_json_str = crypto.decrypt(response.text)
return json.loads(decrypted_json_str)测试用例层只需传入明文参数、拿到解密后的明文结果进行断言,完全感知不到加解密的复杂度。