目录
在接口测试中,参数签名和加密是为了保证请求的安全性和数据的完整性。参数签名将请求参数按照一定规则排序并拼接,加上密钥,然后进行散列(如MD5、SHA1)或HMAC运算,生成签名。服务器端用同样的方法生成签名,对比签名是否一致。加密对敏感数据进行加密传输,常见的加密方式有对称加密(如AES)和非对称加密(如RSA)。
一、参数签名(防篡改)
典型流程
Python示例(MD5签名)
import hashlib
def generate_sign(params, secret_key):
# 1. 过滤空值并按键名排序
sorted_params = sorted([(k, v) for k, v in params.items() if v])
# 2. 拼接键值对 + 密钥
query_str = '&'.join([f"{k}={v}" for k, v in sorted_params])
sign_str = query_str + secret_key # 示例: name=Alice&age=30key123
# 3. 生成MD5签名
return hashlib.md5(sign_str.encode()).hexdigest()
# 使用示例
params = {"name": "Alice", "age": 30, "timestamp": 1697011200}
secret_key = "key123"
sign = generate_sign(params, secret_key) # 输出:fc3e98e8b5c4faf5d5b5a8d4
params["sign"] = sign # 添加签名到请求参数
服务端验证逻辑
接收请求,移除参数中的 sign
用同样算法生成签名
对比客户端和服务端签名是否一致
二、参数加密(防窃取)
场景:敏感数据(如密码、身份证号)加密传输
AES对称加密示例:
from Crypto.Cipher import AES
import base64
import json
def aes_encrypt(data, key, iv):
data = json.dumps(data).encode()
cipher = AES.new(key.encode(), AES.MODE_CBC, iv.encode())
# 填充数据至16字节倍数
pad_len = 16 - (len(data) % 16
data += bytes([pad_len]) * pad_len
ciphertext = cipher.encrypt(data)
return base64.b64encode(ciphertext).decode()
# 使用示例
key = "1234567890abcdef" # 16/24/32字节密钥
iv = "abcdef1234567890" # 16字节初始化向量
data = {"mobile": "13800138000", "id_card": "110101199001011234"}
encrypted_data = aes_encrypt(data, key, iv) # 输出Base64密文
三、完整请求示例(含签名+加密)
请求参数结构
json
{
"app_id": "your_app_id",
"encrypted_data": "AES加密后的数据字符串",
"timestamp": 1697011200,
"nonce": "随机字符串",
"sign": "参数签名"
}
签名生成步骤
组合 app_id + timestamp + nonce + encrypted_data
按字母顺序排序并拼接
app_id=xxx&encrypted_data=xxx&nonce=xxx×tamp=xxx
末尾添加密钥,生成MD5签名
四、测试注意事项
密钥管理
测试环境使用测试专用密钥
禁止硬编码在代码中(推荐从环境变量读取)
时间戳同步
服务端会校验时间戳有效性(如允许±5分钟误差)
随机数防重放
服务端会记录 nonce 防止重复请求
加密模式
AES需确认工作模式(CBC/ECB)和填充方式(PKCS#7)
五、调试工具推荐
Postman
Pre-request Script 实现自动签名
//javascript
// 示例:MD5签名
const secret = pm.environment.get("SECRET_KEY");
let params = Object.assign({}, request.data);
delete params.sign;
const sortedStr = _.chain(params).omit(_.isNull).toPairs().sortBy(0).map(p => p.join('=')).value().join('&');
const sign = CryptoJS.MD5(sortedStr + secret).toString();
pm.environment.set("CURRENT_SIGN", sign);
JMeter
使用 __digest 函数生成MD5
groovy
${__digest(MD5,${param1}${param2}${SECRET},,,)}
签名 = 参数排序 + 密钥拼接 + 哈希运算
加密 = 敏感数据单独加密(AES/RSA)
防重放 = 时间戳 + 随机数