04. 接口加解密测试
2024年10月28日大约 4 分钟
04. 接口加解密测试
1. 项目接口加解密实现分析
加解密说明
⼯作中如果要对加解密怎么做?
1、找开发拷⻉加密和解密⼯具 2、确定⼯具如何使⽤(如何加密、如何解密) 3、明确请求示例(请求参数格式及使⽤)
1. 未加密实现方式
- 提示:以登录接口为例,介绍接口加解密的实现
基本信息
接口名称:登录
请求方式:POST
请求路径:/phone/member/login
请求参数(表单提交)
member_name: 用户名或手机号码或邮箱
password: 密码
返回数据(JSON格式)
{"code":200,"result":"success","data":{"member":{"name":"13012345678"},"login_token":147}}
2. 加解密代码实现(了解)
1. 接口描述
基本信息
接口名称:登录
请求方式:POST
请求路径:/phone/member/login
请求参数(表单提交)
- diyou:加密后的请求数据,把原始请求参数(member_name、password)转换为json字符串再进行加密得到的密文
- xmdy:签名,对加密后的请求数据进行签名
返回数据(JSON格式)
{"xmdy":"df0990efe05976e4ef326dab5bf3fc83","diyou":"xxx"}
- diyou:加密后的响应数据
- xmdy:签名
2. 加解密代码实现-Java实现方式
- 提示:以实际工作中,可以 让开发人员协助封装加解密 方法
/**
加密
@param key 密钥
@param content 待加密数据
@return 加密后的数据
*/
public static String aesEncrypt(String key, String content) {
try {
content = new BASE64Encoder().encodeBuffer(content.getBytes());
content = replaceBlank(content);
SecretKey secretKey = new SecretKeySpec(key.getBytes(), "AES");
Cipher cipher = Cipher.getInstance("AES");
cipher.init(Cipher.ENCRYPT_MODE, secretKey);
byte[] aes_byte = cipher.doFinal(content.getBytes(StandardCharsets.UTF_8));
return new BASE64Encoder().encode(aes_byte);
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
/**
解密
@param key 密钥
@param content 待解密数据
@return 解密之后的数据
*/
public static String aesDecrypt(String key, String content) {
try {
SecretKey secretKey = new SecretKeySpec(key.getBytes(), "AES");
Cipher cipher = Cipher.getInstance("AES");
cipher.init(Cipher.DECRYPT_MODE, secretKey);
byte[] byte_content = new BASE64Decoder().decodeBuffer(content);
byte[] byte_decode = cipher.doFinal(byte_content);
String aes_decode = new String(byte_decode, StandardCharsets.UTF_8);
String aes_decode2 = new String(
new BASE64Decoder().decodeBuffer(aes_decode));
return unicodeToString(aes_decode2);
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
3.加解密代码实现-Python实现方式
加密标准常⽤美国联邦政府⾼级密码标准(AES)
安装依赖包:pip install pycryptodome==3.9.6 -i https://pypi.douban.com/simple
@staticmethod
def aes_encrypt(key, data):
"""
AES加密
:param key: 密钥
:param data: 待加密数据
:return: 加密后数据
"""
data = base64.encodebytes(data.encode()).decode()
# 替换特殊字符
data = EncryptUtil.replace_blank(data)
print("data=", data)
# 初始化加密器
aes = AES.new(key.encode(), AES.MODE_ECB)
# 解密
padding_value = EncryptUtil.padding_pkcs5(data)
encrypt_aes = aes.encrypt(padding_value)
# 用base64转成字符串形式
encrypted_text = base64.encodebytes(encrypt_aes).decode()
return encrypted_text
@staticmethod
def aes_decrypt(key, data):
"""
AES解密
:param key: 密钥
:param data: 待解密数据
:return: 解密后数据
"""
# 初始化加密器
aes = AES.new(key.encode(), AES.MODE_ECB) # 优先逆向解密base64成bytes
base64_decrypted = base64.decodebytes(data.encode())
# 执行解密
decrypted_bytes = base64.decodebytes(aes.decrypt(base64_decrypted))
# 转换为字符串
decrypted_text = str(decrypted_bytes, encoding="utf-8")
# 把Unicode转成中文
result = decrypted_text.encode().decode("unicode_escape")
return result
2. Python+Requests实现加解密测试
- 实现步骤:
- 构造测试数据
- 对请求参数进行加密
- 发送请求
- 对响应数据进行解密
- 断言
class TestMobile(unittest.TestCase):
def test_login(self):
"""登录"""
url = "http://mobile-p2p-test.ithiema.net/phone/member/login"
# 请求参数
req_data = {
"member_name": "13012345678", "password": "test123"
}
# 对请求参数进行加密,并获取签名
diyou = EncryptUtil.get_diyou(req_data)
xmdy = EncryptUtil.get_xmdy(diyou)
# 发送请求
r = requests.post(url, data={"diyou": diyou, "xmdy": xmdy})
print("r.text==", r.text)
# 对响应数据进行解密
json_data = r.json()
diyou_data = json_data.get("diyou")
decrypted_data = EncryptUtil.decrypt_data(diyou_data)
print("decrypted_data=", decrypted_data)
# 断言
json_data = json.loads(decrypted_data)
self.assertEqual(200, json_data.get("code"))
self.assertEqual("success", json_data.get("result"))
3. JMeter实现加解密测试
实现步骤
- 在Java项目中封装加解密方法,并导出jar包
- 在JMeter中引入依赖的jar包(包括:加解密jar包、以及其他依赖的jar包)
- 把jar包放到JMeter的lib\ext目录下
- 在测试计划-->添加目录或jar包到ClassPath,添加需要调用的jar包
- 在‘HTTP请求’取样器下添加前置处理器‘BeanShell PreProcessor’,并编写对请求数据进行加密的代码
- 在‘HTTP请求’取样器下添加后置处理器‘BeanShell PostProcessor’,并编写对响应数据进行解密代码
- 在‘HTTP请求’取样器下添加断言‘BeanShell断言’,对返回数据进行断言
前置处理脚本(实现请求数据加密)
log.info("==============================" + sampler.getName() + "=============================="); import cn.tt.p2p.EncryptUtil; import org.apache.jmeter.config.*; // 获取请求参数 TreeMap map = new TreeMap(); Arguments args = sampler.getArguments(); for(int i=0; i<args.getArgumentCount(); i++){ Argument arg = args.getArgument(i); String name = arg.getName(); String value = arg.getValue(); log.info("name="+name+" value="+value); map.put(name, value); } // 加密 String diyou = EncryptUtil.getDiyou(map); String xmdy = EncryptUtil.getXmdy(diyou); // 添加请求参数 sampler.addArgument("diyou", diyou); sampler.addArgument("xmdy", xmdy);
后置处理脚本(实现响应数据解密)
import cn.tt.p2p.EncryptUtil; import org.json.*; // 获取响应数据 String responseStr = prev.getResponseDataAsString(); log.info("responseStr=" + responseStr); JSONObject responseJson = new JSONObject(responseStr); // 获取响应数据diyou String diyou_data = responseJson.getString("diyou"); log.info("diyou_data="+diyou_data); // 解密 String jsonDataStr = EncryptUtil.decryptDiyou(diyou_data); log.info("jsonDataStr=="+jsonDataStr); // 添加到变量列表中 vars.put("jsonDataStr", jsonDataStr);
BeanShell断言
import org.json.*; // 获取解密之后的响应数据 String jsonDataStr = vars.get("jsonDataStr"); JSONObject jsonData = new JSONObject(jsonDataStr); // 断 言 - code if(jsonData.getInt("code") != 200){ Failure = true; FailureMessage = "code的返回值有误"; }