JMeter处理接口签名(sign)

先贴脚本, 大神请直取

  • 新建线程组 → http取样器 → 前置处理器 → bean shell 预处理程序

    import org.apache.commons.codec.digest.DigestUtils; 
    import java.util.Date;
    //没有第三方jar包,请放心 import
      
    Date date = new Date();
    //将时间戳截取到秒的量级(长度共10位),大神可以考虑地板除,弟中弟请当没看见
    String timestamp = String.valueOf(date.getTime()/1000);
    //将时间戳赋值给ts变量,方便以 ${ts} 的方式引用
    vars.put("ts",timestamp);
      
    //此处的SPhone的值可以用csv参数化
    String data = "{\"SPhone\":\"18662255783\",\"EType\":0}";
    
    String key = "a323f9b6-1f04-420e-adb9-b06ty67b0e63";
    
    String bsign = "z417App" + timestamp + data + key;
    
    //MD5加密赋值给sign变量
    vars.put("sign",DigestUtils.md5Hex(bsign));
    

小白请从这里看起

REST api大多会传sign(签名)字段,各接口对sign的内容、方式可能不一样,但一般模式都是从接口的入参中选择部分内容组成一个字符串,然后再拼接一个secretKeyappKey(秘钥,值固定), 最后对这个拼接起来的字符串进行MD5的运算, 将结果赋值给sign; 完整规范的接口文档都会有sign的算法描述。

解题思路

  1. 找到签名算法:接口文档为准,secretKey 或 appKey 可以问开发要;

  2. 接口的传入的参数不改变,则sign的值就不变:利用这点可以先用接口测试工具(如postman)调试下接口, 在线MD5请移步站长工具

  3. 接口手动调通了,接下来翻译到工具的脚本语言中:说的比较晦涩,继续往下看吧;

  4. 特别注意:如果待签名的内容中有中文,需要特别处理下!!踩过坑(这部分会在loadrunner如何处理sign的博客中记录,先挖个坑,以后填)。

接口入参示例

  • 以下是一个传入手机号获取短信验证码的请求消息

    {
        "AppKey": "z417App",
        "AppVer": "1.0.0",
        "Data": "{\"SPhone\":\"18662255783\",\"EType\":0}",
        "DeviceName": "web",
        "DeviceType": "web",
        "Lang": "CN",
        "Sign": "8011fd9bdacd3372103053b43bef76e7",
        "TimeStamp": 1560584745
    }
    

初步分析

  1. 这是一串json消息:post方式发送

  2. 里面套的Data字段的值有点像json:Data的值是个字符串,不是内层 json

  3. SPhone的值是字符串格式的电话号码:可能是个动态变化的,得用参数化处理下,使它变化起来

  4. sign应该就是今天的主角:sign的算法请仔细阅读接口文档,实在看不懂就问开发

  5. TimeStamp时间戳:一个精确到秒的时间戳

确定可能会动态变换的入参

  1. SPhone字段

  2. Sign字段

  3. TimeStamp字段

签名算法

AppKey + TimeStamp + Data + secretKey 的值拼接在一起组成一个新的字符串,对该字符串进行MD5(32位[小])的运算。(tps:站长工具)

  • 举个不能吃的栗子:
    AppKey 的值是 "z417App"

    TimeStamp 的值是 1560584745

    Data 的值是 "{\"SPhone\":\"18662255783\",\"EType\":0}"

    secretKey 的值是 "a323f9b6-1f04-420e-adb9-b06ty67b0e63"

    ⑤ 拼接成一个字符串:

    z417App1560584745{\"SPhone\":\"18662255783\",\"EType\":0}a323f9b6-1f04-420e-adb9-b06ty67b0e63
    

    ⑥ MD5运算后的值:8011fd9bdacd3372103053b43bef76e7 → 就可以赋给Sign了

  • 再举个不能吃的栗子:(其他签名算法)

从所有入参中筛选出参数的值不为空(null,"")的集合,将集合中的参数名按照ASCII码从小到大排序(像英语词典), 使用URL键值对的格式(即key1=value1&key2=value2…)拼接成字符串(sign字段不参与拼接),假设是str1;在str1最后拼接上key=secretKey,得到更长的一个字符串,假设是str2。对str2进行MD5运算,再将得到的字符串转换为大写

  • 入参举例:

    {
        "appid": "wxd930u",
        "mch_id": 10100,
        "device_info": 100,
        "body": "{\"EType\":0}",
        "DeviceType": "",
        "nonce_str": "ibuaiVc",
        "sign": "CD198C36632A274C49E5F2F028FA257C",
        "source": null
    }
    
  • 第一步:按字典序对有值的入参、按url键值对的方式进行拼接

    String str1 = "appid=wxd930u&body={\"EType\":0}&device_info=100&mch_id=10100&nonce_str=ibuaiVc";
    
  • 第二步:拼接API密钥(secretKey的值:a323f9b6):

    String str2 = str1 + "&key=a323f9b6";
    
  • 第三步:签名MD5(32位[大],可用站长工具)

    /** 
    * 注意java中有自带的MD5方法,是16位以16个元素的形式返回值,大神请自己写,弟中弟请用已有的jar
    * md5hex是以32位16进制的小写字符串形式返回
    */
    String sign = DigestUtils.md5Hex(str2).toUpperCase();
    // 即 sign = "CD198C36632A274C49E5F2F028FA257C"
    

再看bean shell脚本

import org.apache.commons.codec.digest.DigestUtils; // DigestUtils类中有md5算法 
import java.util.Date; // Date类中有获取当前时间戳方法
//没有第三方jar包,请放心 import

Date date = new Date(); // 创建Date对象,取名叫date
//将时间戳截取到秒的量级(长度共10位),大神可以考虑地板除,弟中弟请当没看见
String timestamp = String.valueOf(date.getTime()/1000);
//将时间戳赋值给ts变量,方便以 ${ts} 的方式引用
vars.put("ts",timestamp);

//此处的SPhone的值可以用csv参数化
String data = "{\"SPhone\":\"18662255783\",\"EType\":0}";
String key = "a323f9b6-1f04-420e-adb9-b06ty67b0e63"; // 要拼接的secretKey
String bsign = "z417App" + timestamp + data + key; // 拼接

//MD5加密后,赋值给sign变量
vars.put("sign",DigestUtils.md5Hex(bsign));

在http的取样器中使用 ts 和 sign 的值

{
    "AppKey": "z417App",
    "AppVer": "1.0.0",
    "Data": "{\"SPhone\":\"18662255783\",\"EType\":0}",
    "DeviceName": "web",
    "DeviceType": "web",
    "Lang": "CN",
    "Sign": "${sign}",
    "TimeStamp": ${ts}
}

问题思考

  1. 前面的例子是建立在request body不变的情况下才能成立,如果request body变化呢?比如对手机号(Sphone)做了参数化。处理方式有两种,请戳 jmeter处理动态的签名(sign)内容

  2. 欢迎交流指正

posted @ 2020-10-09 15:24  z417  阅读(3548)  评论(0编辑  收藏  举报